FragmentでsetRetainInstance(true)としていると、loaderのonLoadFinished()が呼ばれないことがある。
そのため、loaderを使っている場合は、setRetainInstance(true)としてはいけない。
自作アプリでloaderとsetRetainInstance(true)を混ぜて使っていて、なぜかonLoadFinished()が呼ばれないことがあるのでググってみたら、Dianne Hackborn(Googleの人)もloaderとsetRetainInstance()を混ぜて使うなと言っていた。
以下の方法で、「onLoadFinished()が呼ばれない場合」を再現できる(GalaxyNexus + JellyBeanで確認)。
ソースコード
Googleによるサンプルコードに従った書き方をしている。onActivityCreated()でinitLoader()をし、onLoaderReset()でswapCursor(null)している。
public class MyFragment extends ListFragment implements LoaderManager.LoaderCallbacks{ private MyAdapter adapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); adapter = new MyAdapter(getActivity()); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); getLoaderManager().initLoader(0, null, this); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); setListAdapter(adapter); } @Override public void onDestroyView() { super.onDestroyView(); setListAdapter(null); } @Override public Loader onCreateLoader(int id, Bundle args) { return new CursorLoader(getActivity(), ...); } @Override public void onLoadFinished(Loader loader, Cursor data) { adapter.swapCursor(data); } @Override public void onLoaderReset(Loader loader) { adapter.swapCursor(null); } }
手順
- 携帯を横(landscape)にしておく。この状態ではListFragmentにCursorの中身が表示されている。
- 電源ボタンを押して、スリープに入れる。
- 携帯を縦に持ちかえる。電源ボタンを押してスリープを解除し、ロックも解除する。すると、ListFragmentの表示が空になっている。
何が起きているのか
電源ボタンを押してスリープに入れた時に、以下の順でcallbackが呼ばれる。
- onLoaderReset
- onDestroyView
- onViewCreated
- onActivityCreated
ロック画面が縦だからだと思うのだが、landscapeのActivityが破棄され、portlaitのActivityが再生成される。 onLoaderReset()は呼ばれているが、Activity再生成後のonLoaderFinish()は呼ばれていない。そのため、スリープとロックを解除すると、ListFragmentが空になっている。
対処方法
setRetainInstance(true)を呼ばない、というのが一番確実な対処方法だが、onActivityCreatedでinitLoader()ではなくrestartLoader()を呼ぶという方法でも、試した限り動作するようだ。ただしrestartLoader()を使う方法だと、多少無駄にqueryを行うことになる。
0 件のコメント:
コメントを投稿