執筆中
目次
参考にするリンク
- Androidが問題と認識してる?ようなIssue
- http://code.google.com/p/android/issues/detail?id=20791
LoaderManagerがonLoadFinished/onLoaderResetを返してくれないことがある
参考にするリンクにあるコメントを抜粋する感じ、バグっぽい。
Revision 4 of ACL fixed part of the bug but it still remains in some cases.
If you take the project posted and run it, press the button to launch the new activity,
switch orientations only once and then press BACK, it shows the wrong value.
The idea is to press BACK from the second activity
while it's in a different orientation than the initial activity (if that makes sense).
For example, activity A is in portrait, press button, switch orientation of activity B to landscape,
press BACK and then enjoy the bug.
私も同じ症状に悩まされたことがあるのだが、
AsyncTaskLoaderを実行中に縦横を切り替えると、
LoaderManagerが保持していたLoaderCallbacksの紐付けをActivityのonDestroy()が呼ばれたタイミングで切るために起こる様子。
このバグを追っかけてみたところ、いくつかの回避案は思いついたのだが、諦めてServiceにした方が心休まると思う。
「返さない」のではなく「返せない」。AsyncTaskの動作背景。
少し前段階のLoaderManagerの動作から埋めていくことにする。
AsyncTaskLoaderの動作をソースから知るのまとめに記載したのだが、
実はLoaderManagerの初期化はActivity#onCreate()でやる必要がある。
呼ぶのはLoaderManager#initLoader()。
これはActivityのLifecycleに混ぜ込んだ時にそういう風に組んでいるのでしょうがない。
で、この初期化はAcitivity初回起動時は当然必要になるのだけれど、
加えて縦横切り替え時にも必要になるのだ。
理由は簡単で、LoaderManagerのインスタンスはActivityが所持しているので、その親が消えれば当然子も消える。
なので初期化する。
しかしどういうわけか、設定しておいたLoaderCallbacksを引き継がないように設計している!!!
これでは同時にLoaderCallbacksも登録が消えてしまうので、
実行中になっていたWorkerThreadであるLoaderCallbacksが応答を返しても受け取り先のLoaderManagerが無い。
ゆえに縦横切り替え後の画面に応答を「返せない」のだ。
回避方法の考察
私がこの問題に直面した時点で、まぁもう後戻りはできなかったので回避方法を考案して導入した。
しかしハッキリ言ってこれは応急処置で、その後も不可思議な問題に何度も直面して修正を加えた。
諦めてServiceをbindした方がいい。
念のため、当時対応した内容を思い出しながら書くと
- LoaderManagerに渡すLoaderCallbacksを次回に引き継いで、Activity#onCreate()で再設定する
- AsyncTaskLoader.deliverResult(D)をオーバーライドして、自分の返却先が無い場合はDを自身の中に覚える
- 回転中にWorkerThreadが終わると返却用データが揮発するので自分で覚える
- Activityが復帰した際のAsyncTaskLoader.onStartLoading()で上記deliverResult(D)で覚えたデータが無いか確認する
という感じだったと思う。(対応時のソースが手元にないため確認できない・・・)
まとめ
関連リンク
取得中です。
&trackback()
最終更新:2012年10月17日 03:01