android 呼ばれない - onActivityResult()内でFragmentTransactionをコミットしても安全ですか?




から 終了 (2)

情報源に少し飛び込む

FragmentManagerクラス内には、 mStatedSavedというブール変数があります。 この変数はアクティビティのライフサイクルコールバックに応じて保存された状態を追跡します。 これがよく知られた例外を投げる方法です。


    private void checkStateLoss() {
        if (mStateSaved) {
            throw new IllegalStateException(
                    "Can not perform this action after onSaveInstanceState");
        }
        ...
    }

つまり、この変数がfalseに変更されるとすぐに、フラグメントトランザクションは自由に実行されます。 この変数は、アクティビティの状態が保存されているとき、つまりonSaveInstanceState()ときにtrueなりtrue

質問に戻る

あなたは、以前はonActivityResult()からトランザクションをコミットするのに問題があったと述べました。 つまり、以前のmStateSavedfalseが割り当てられていなかったのですが、現在はそうです。 実際にそうです。

これはOリリースのonActivityResult()実装です。


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        mFragments.noteStateNotSaved();
        ...
    }

noteStateNotSaved()は次のようになります。


    public void noteStateNotSaved() {
        ...
        mStateSaved = false;
        ...
    }

それどころか、Jelly BeanリリースのonActivityResult()実装を見ることができます。


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        int index = requestCode>>16;
        if (index != 0) {
            index--;
            if (mFragments.mActive == null || index = mFragments.mActive.size()) {
                Log.w(TAG, "Activity result fragment index out of range: 0x"
                        + Integer.toHexString(requestCode));
                return;
            }
            Fragment frag = mFragments.mActive.get(index);
            if (frag == null) {
                Log.w(TAG, "Activity result no fragment exists for index: 0x"
                        + Integer.toHexString(requestCode));
            } else {
                frag.onActivityResult(requestCode&0xffff, resultCode, data);
            }
            return;
        }

        super.onActivityResult(requestCode, resultCode, data);
    }

mStateSavedフィールドの値は何も変更されず、トランザクションがコミットされた場合にスローされる例外が発生します。

実際、 mFragments.noteStateNotSaved()という行がKit-Katのリリースで導入されました。 Dianne Hackbornによるコミットのコメントからわかるように、

ActivityFragmentは、 onNewIntent()を受け取ったときにstateが保存されているというフラグをクリアする必要があります。 これはアクティビティが再開される前に発生する可能性があるため、まだクリアしていない可能性があります。 onActivityResult()についても同じことをする必要があります。

まとめる

onActivityResult()がフラグメントトランザクションの安全な場所になることが保証されていますか?

2012年10月に作成されたcommit 4ccc001を含むソースを使用していると仮定します。そう、フラグメントトランザクションにとって安全な場所です。

何年も前に、私は自分のonActivityResult()コールバックの中でFragmentTransactionをコミットしようとしたときに、私のアプリケーションの1つで問題に遭遇しました。 グーグルを回って、私はこの質問と答えを見つけた、それは言う

onActivityResult()が呼び出された時点では、activity / fragmentの状態はまだ復元されていない可能性があるため、この間に発生したトランザクションは結果として失われます。

私は自分のアプリに同じ答えで推奨されている解決策を適応させることにした、そして人生はよかった。 しかし、最近の実験ではおそらく状況が変わったことが示されているので、 onActivityResult()内部からFragmentTransactionをコミットしても安全な場合があります。

FragmentManager.beginTransaction() (support v4)ドキュメントでは、トランザクションに対する安全なウィンドウを次のように定義しています。

注:フラグメントトランザクションは、アクティビティが状態を保存する前にのみ作成またはコミットできます。 FragmentActivity.onSaveInstanceState()後(および次のFragmentActivity.onStartまたはFragmentActivity.onResume()FragmentActivity.onSaveInstanceState()トランザクションをコミットしようとすると、エラーが発生します。

onActivityResult()ドキュメントを読むと

アクティビティが再開されると、 onResume()直前にこの呼び出しを受け取ります。

これは、 onStart()がすでに呼び出されているので、 onActivityResult()でこれらのトランザクションを実行するのが安全であるべきだと私に信じさせます。

これをテストするためのアプリを作成しましたが、 onActivityResult()中で作成およびコミットするダイアログフラグメントが正常に表示されています。 私は同じアプリでアクティビティのライフサイクルコールバックもログに記録し、順番を確認できるようにしました。そして、 onRestoreInstanceState() onStart() 、次にonRestoreInstanceState() 、そしてonActivityResult()れます。

私は何かが足りないのですか? それともフレームワークが変更され、 onActivityResult()がフラグメントトランザクションの安全な場所になることが保証されていますか? この動作はAPIレベルによって異なりますか?

私は私が持っているのと同じ方法でドキュメンテーションを読むように思われる別の質問と答えを見つけました、しかし両方とも1年以上前のもので、どちらもトランザクションの安全な場所としてonActivityResult()を特に言及しません。


アクティビティからログイン状態を抽象化することを検討することをお勧めします。 たとえば、ユーザーがコメントを投稿できる場合は、onPostアクションをログイン状態にpingしてから、アクティビティ状態ではなくそこから移動します。





android android-fragments android-activity android-fragmentactivity fragmentmanager