バックグラウンド
Android での非同期コールバック
Android で信頼性の高い方法で非同期操作を実行しようとすると、不必要に複雑になります。つまり、AsyncTask は本当に概念的に欠陥があるのでしょうか、それとも単に何かが足りないのでしょうか?
さて、これはすべて Fragments の導入前です。フラグメントの導入により、onRetainNonConfigurationInstance()は非推奨になりました。そのため、Google が容認する最新のハックは、構成の変更 (画面の回転、言語設定の変更など) が発生したときにアクティビティにアタッチ/デタッチする永続的な非 UI フラグメントを使用することです。
例: https://code.google.com/p/android/issues/detail?id=23096#c4
IllegalStateException - onSaveInstanceState の後でこのアクションを実行できない
理論的には、上記のハックにより、恐ろしいことを回避できます。
IllegalStateException - "Can not perform this action after onSaveInstanceState"
永続的な非 UI フラグメントが onViewStateRestored() (または onResume) および onSaveInstanceState() (または onPause) のコールバックを受け取るためです。そのため、インスタンスの状態がいつ保存/復元されるかがわかります。これは非常に単純なコードですが、この知識を利用すると、アクティビティの FragmentManager の mStateSaved 変数が false に設定されるまで、非同期コールバックを実行する前にキューに入れることができます。
mStateSaved は、この例外の発生を最終的に担当する変数です。
private void checkStateLoss() {
if (mStateSaved) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
if (mNoTransactionsBecause != null) {
throw new IllegalStateException(
"Can not perform this action inside of " + mNoTransactionsBecause);
}
}
理論的には、フラグメント トランザクションを安全に実行できるタイミングがわかったので、恐ろしい IllegalStateException を回避できます。
違う!
ネストされたフラグメント
上記のソリューションは、アクティビティの FragmentManager に対してのみ機能します。フラグメント自体にも、フラグメントのネストに使用される子フラグメント マネージャーがあります。残念ながら、子フラグメント マネージャーはアクティビティのフラグメント マネージャーとまったく同期していません。そのため、アクティビティのフラグメント マネージャーは最新であり、常に正しい mStateSaved を持っています。子フラグメントは別の方法で考え、不適切なときに恐ろしい IllegalStateException を喜んでスローします。
さて、サポート ライブラリの Fragment.java と FragmentManager.java を見たことがあれば、フラグメントに関係するすべてのことがエラーを起こしやすいことに驚かないでしょう。デザインとコードの品質は...ああ、疑わしいです。ブーリアンは好きですか?
mHasMenu = false
mHidden = false
mInLayout = false
mIndex = 1
mFromLayout = false
mFragmentId = 0
mLoadersStarted = true
mMenuVisible = true
mNextAnim = 0
mDetached = false
mRemoving = false
mRestored = false
mResumed = true
mRetainInstance = true
mRetaining = false
mDeferStart = false
mContainerId = 0
mState = 5
mStateAfterAnimating = 0
mCheckedForLoaderManager = true
mCalled = true
mTargetIndex = -1
mTargetRequestCode = 0
mUserVisibleHint = true
mBackStackNesting = 0
mAdded = true
というか、ちょっと話が脱線。
行き止まりの解決策
そのため、この問題の解決策は簡単だと思うかもしれませんが、これはこの時点では少し反意語のように思えますが、別の素敵なハッキーな非 UI フラグメントを子フラグメント マネージャーに追加することです。おそらく、そのコールバックは内部状態と同期しており、物事はすべてうまくいくでしょう。
再度間違える!
Android は、他のフラグメント (ネストされたフラグメント) に子としてアタッチされている保持フラグメント インスタンスをサポートしていません。さて、後から考えると、これは理にかなっているはずです。保持されていないためにアクティビティが破棄されたときに親フラグメントが破棄された場合、子フラグメントを再アタッチする場所がありません。だから、それはうまくいきません。
私の質問
非同期コード コールバックと組み合わせて、子フラグメントでフラグメント トランザクションを安全に実行できるかどうかを判断するためのソリューションを誰かが持っていますか?