ひらい ぶらり Hi-Library

ぷろぐらみんぐについて。ときどきどうでもいいことについて。

FragmentPagerAdapterでnotifyDataSetChangedを呼んでも更新されない

結論

FragmentStatePagerAdapterを使え、でも問題はたくさんあるから油断をしてはいけない

※追記あり

FragmentStatePagerAdapterを使えと言ったな、あれは嘘だ - ひらい ぶらり Hi-Library

解決する内容

FragmentStatePagerAdapterは、destroyItemでfragmentをremoveしているので、notifyDataSetChangedを呼べば新しくgetItemで呼ばれたデータを元にFragmentが生成される。

解決しない内容

ただしsavedStateは残り続ける。以下のような場合カオスなことになる。

  1. Fragment内部にEditViewがあり、1ページ目に『ほげ』と入力された。
  2. notyfyDataSetChanged()
  3. Fragmentが再生成される。ただしsavedStateを渡して再生成されるので、Fragment内部に1と同じIDを持つEditViewがあれば『ほげ』が入力された状態で生成される

書いてて思ったけど、Fragmentの挙動としては正しい・・・のか? ともかく、気にしていないとわけも分からず想定しない動きをするのでFragment周りはソースをよく見ておいた方がいいということだけは肝に銘じておこうと思った。 viewのIDを変えれば回避できることだし、fragment的に考えたら再生成されたら復元されるのだろう。(大体余計なお世話であることのほうが多いけど)

結論その2

保持するアイテム数が少なく、絶対に更新されない場合→FragmentPagerAdapterを使う それ以外→FragmentStatePagerAdapterを使う

メモリを圧迫せず、データも更新されないならばFragmentPagerAdapterを使ったほうが、動作は早くなるハズ。でも大体FragmentStatePagerAdapterを使うことになると思う。

ここからチラシ裏

問題を解決するために色々見てたら以下の記事を見つけた。

outofmem.hatenablog.com

この記事はFragmentAdapterの使い方と言うよりは、FragmentPagerAdapter is クソみたいな話をします。

全面的に同意で、思ったことは自前でmakeFragmentNameメソッドを作らずにinstantiateItemメソッドを使えばいいんじゃないかなぐらい。書かれた時期が1年以上前なので何を今更感はあるかも。

あと、会社のパイセンと話していたらsupport libraryがバージョンアップして新たに getItemIdメソッドが実装されていることを教えてもらった。(4.1.2_r1から追加されてた) getItemIdでタグの生成をviewPager.getId() + position から、getItemで取れるなにがしかのIDをに変えてやれば問題は解決した。でもFragmentはマネージャーによって保持され続けるので、よっぽどのことがなければFragmentStatePagerAdapterを使うほうがよさそう。

Fragment周りはしょっちゅうトラブルが起きて、理解が浅いんだなーと思って調べれば調べるほどキモい気もするし、もしかしてこういうこと?あれ?ひょっとしてFragmentってちゃんと使えばすごく便利なん・・・そんなことねーやの繰り返しなきもしますが、これからも頑張ってFragmentと付き合っていこうと思います。