システムの「メモリ再起動」後、ActivityとFragmentのライフサイクルについて

10903 ワード

前言


昨日、ActivityとFragmentのライフサイクル呼び出しの前後順位に関するオンライン問題を特定しました.今日はこの問題を記録します.

通常のプロセス


まず、公式に与えられたライフサイクルフローチャートを見てみましょう.
この3枚の図は分かりやすく、あまり言わないで、ActivityとFragmentのライフサイクルがどのように交差して呼び出されているかを見てみましょう.Activityクラスを書き、Fragmentを動的に追加し、コードを簡単に貼り付けます.
一般的にonCreateでfragmentを作成しActivityに追加し、コードを実行します.
1、アプリが正常に起動した時のロゴを見る:
2、フロントからバックグラウンドに入る時のロゴ:
3、バックグラウンドからフロントに入る時はlog:
4、アプリを正常に閉じる時のロゴ:
これらは簡単です.もう一つのケースとして、アプリがバックグラウンドに退いた後、携帯電話のメモリが緊張してシステムに殺された場合、アプリを再起動してライフサイクルはどうなるのでしょうか.携帯電話のメモリが低いアプリが殺された後、再びアプリを開いた時のロゴ:
02-25 18:38:07.304 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onAttach: FragmentA{f756b52 #0 id=0x7f070037}
02-25 18:38:07.304 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onCreate: FragmentA{f756b52 #0 id=0x7f070037}
02-25 18:38:07.305 10048-10048/com.test.wxl D/LifeCycle_ActivityA: onCreate: 
02-25 18:38:07.568 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onCreateView: FragmentA{f756b52 #0 id=0x7f070037}
02-25 18:38:07.580 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onActivityCreated: FragmentA{f756b52 #0 id=0x7f070037}
02-25 18:38:07.582 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onAttach: FragmentA{5e5374e #1 id=0x7f070037}
02-25 18:38:07.582 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onCreate: FragmentA{5e5374e #1 id=0x7f070037}
02-25 18:38:07.583 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onCreateView: FragmentA{5e5374e #1 id=0x7f070037}
02-25 18:38:07.591 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onActivityCreated: FragmentA{5e5374e #1 id=0x7f070037}
02-25 18:38:07.592 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onStart: FragmentA{f756b52 #0 id=0x7f070037}
02-25 18:38:07.593 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onStart: FragmentA{5e5374e #1 id=0x7f070037}
02-25 18:38:07.594 10048-10048/com.test.wxl D/LifeCycle_ActivityA: onStart: 
02-25 18:38:07.603 10048-10048/com.test.wxl D/LifeCycle_ActivityA: onResume: 
02-25 18:38:07.608 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onResume: FragmentA{f756b52 #0 id=0x7f070037}
02-25 18:38:07.609 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onResume: FragmentA{5e5374e #1 id=0x7f070037}

どういうことか、通常開いているときのライフサイクルの流れとは違って、logを見て、fragmentに関する情報はActivity呼び出しonSaveInstance()メソッドで保存されているはずだと大胆に推測します.まずonCreate(@Nullable Bundle savedInstanceState)のsuperにフォローします.onCreate(savedInstanceState)メソッド、最終的にFragmentActivityのonCreate(@Nullable Bundle savedInstanceState)メソッドに来て、コードを貼って見てみました
この方法では、mFragmentsが最終的に呼び出されたのを見ることができます.dispatchCreate()は、FragmentManagerがFragmentライフサイクルを管理するのに役立つ集合です.dispatchCreate()メソッドに従ってみてください.
public void dispatchCreate() {
        mStateSaved = false;
        dispatchStateChange(Fragment.CREATED);
    }

途中でFragmentMannagerが呼び出されます.JAvaのdispatchCreate()メソッドは、最終的にFragmentManagementに来ました.JAvaのmoveToState(int newState,boolean always)メソッドは、コードを貼ってみてください
void moveToState(int newState, boolean always) {
    // 
    mCurState = newState;// 1

    if (mActive != null) {
        boolean loadersRunning = false;

        // Must add them in the proper order. mActive fragments may be out of order
        // Fragment 
        final int numAdded = mAdded.size();
        for (int i = 0; i < numAdded; i++) {// 2
            Fragment f = mAdded.get(i);
            moveFragmentToExpectedState(f);// 3
            if (f.mLoaderManager != null) {
                loadersRunning |= f.mLoaderManager.hasRunningLoaders();
            }
        }

        // Now iterate through all active fragments. These will include those that are removed
        // and detached.
        // detached frament 
        final int numActive = mActive.size();
        for (int i = 0; i < numActive; i++) {
            Fragment f = mActive.valueAt(i);
            if (f != null && (f.mRemoving || f.mDetached) && !f.mIsNewlyAdded) {
                moveFragmentToExpectedState(f);
                if (f.mLoaderManager != null) {
                    loadersRunning |= f.mLoaderManager.hasRunningLoaders();
                }
            }
        }

        if (!loadersRunning) {
            startPendingDeferredFragments();
        }

        if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
            mHost.onSupportInvalidateOptionsMenu();
            mNeedMenuInvalidate = false;
        }
    }
}

注記1でmCurState変数を代入する、すなわち、伝えたばかりのFragment.CREATED. 注釈2のループを見てここではmAddedについて簡単に説明するが、mAddedはFragmentオブジェクトが保存されたリストであり、listのfragmentのstateはFragmentである.INITIALIZING型で、このリストのオブジェクトは、FragmentがFragmentManagerによってaddおよびcommitを呼び出された最初の時点で追加されます.次に注釈3を見てみると,最終的にmoveToState(Fragment f,int newState,int transit,int transitionStyle,boolean keepActive)メソッドが呼び出され,伝達されたパラメータnewStateは先ほど述べたmCurStateであり,以下のようになる.
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
           boolean keepActive) {
       // Fragments that are not currently added will sit in the onCreate() state.
      // 
       if (f.mState <= newState) {
           // 
           // Fragment f mState=Fragment.INITIALIZING =0
           switch (f.mState) {
               case Fragment.INITIALIZING:
                // newState = Fragment.CREATED=1
                   if (newState > Fragment.INITIALIZING) {
                      // 

                       f.mHost = mHost;
                       f.mParentFragment = mParent;
                       f.mFragmentManager = mParent != null
                               ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();

                       // If we have a target fragment, push it along to at least CREATED
                       // so that this one can rely on it as an initialized dependency.
                       if (f.mTarget != null) {
                           if (f.mTarget.mState < Fragment.CREATED) {
                               moveToState(f.mTarget, Fragment.CREATED, 0, 0, true);
                           }
                       }

                       dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
                       f.mCalled = false;
                       // 
                       f.onAttach(mHost.getContext());// 3
                       //.....
                       if (f.mParentFragment == null) {
                           mHost.onAttachFragment(f);
                       } else {
                           f.mParentFragment.onAttachFragment(f);
                       }
                       dispatchOnFragmentAttached(f, mHost.getContext(), false);

                       if (!f.mIsCreated) {
                           dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
                           f.performCreate(f.mSavedFragmentState);
                           dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
                       } else {
                           f.restoreChildFragmentState(f.mSavedFragmentState);
                           f.mState = Fragment.CREATED;
                       }
                       f.mRetaining = false;
                   }
                   // fall through
                    // 
           }
       }

       if (f.mState != newState) {
           Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
                   + "expected state " + newState + " found " + f.mState);
           // 
           f.mState = newState;
           
       }
   }

注釈3のところ、FragmentのonAttached()メソッドを呼び出し、ルーツを見つけました.そこで、Appがメモリの緊張で殺された後、再びAppを開くと、FragmentのonAttachedメソッドはFagmentがコミットトランザクションを追加する前に実行される現象が見られた.

まとめ


振り返ってみるとActivity AのonCreate()にFragmentを追加する書き方が正しいかどうか、上記の研究では、携帯電話のメモリが低下し、システムに殺される前にFragment関連の情報がシステムによって保存され、再びアプリを開くと、onCreate(@Nullable Bundle savedInstancesState)のパラメータから直接取ることができ、上記のような書き方を押していると、Fragmentを繰り返し追加することがわかります.これにより、メモリの消費、リソースの浪費など、いくつかの列の問題が発生します.正しい書き方は次の通りです.
   @Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
       Log.d(TAG, "onCreate: before super");
       super.onCreate(savedInstanceState);
       Log.d(TAG, "onCreate: ");
       setContentView(R.layout.activity_a);

       if (savedInstanceState!=null){
           fragment = getSupportFragmentManager().findFragmentByTag("ActivityA");
           return;
       }
       fragment = new FragmentA();
       fragmentManager = getSupportFragmentManager();
       FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
       fragmentTransaction.add(R.id.fragment_container,fragment,"ActivityA");
       fragmentTransaction.commit();
   }

最后に文章が悪くないと思って、好きな人にほめてあげましょう.