Activity与Fragment生命周期的一些观察和思考

Activity与Fragment的生命周期是一个老生常谈的话题,网上最常见的图是这个:


fragment1.png

还有这个:


fragment2.png

但是这个图并没有说明Activity和Fragment的每个阶段下,是Fragment的方法先调用还是Activity的方法先调用。于是我尝试了探究了一下。

场景一

我的代码如下:
Activity1.java

public class Activity1 extends AppCompatActivity {
    FragmentManager fragmentManager;
    FrameLayout frameLayout;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        log("onCreate");
        setContentView(R.layout.activity_simple);
        frameLayout = (FrameLayout) findViewById(R.id.container);
        fragmentManager = getSupportFragmentManager();
         if (savedInstanceState == null) {
            fragmentManager.beginTransaction()
                    .add(R.id.container,SimpleFragment1.getInstance("fragment") , "fragment")
                    .commit();
        }
    }
    @Override
    protected void onStart() {
        super.onStart();
        log("onStart");
        frameLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }
    @Override
    protected void onResume() {
        super.onResume();
        log("onResume");
    }
    @Override
    protected void onPause() {
        super.onPause();
        log("onPause");
    }
    @Override
    protected void onStop() {
        super.onStop();
        log("onStop");
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        log("onDestroy");
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        log("onSaveInstanceState");
    }
    private void log(String s) {
        Log.i("tag", "Activity1 -- " + s);
    }
}

SimpleFragment1.java

public class SimpleFragment1 extends Fragment {
    private String str;
    private int num=1;
    public SimpleFragment1() {
    }
    public static SimpleFragment1 getInstance(String s) {
        SimpleFragment1 fragment = new SimpleFragment1();
        Bundle b = new Bundle();
        b.putString("string", s);
        fragment.setArguments(b);
        return fragment;
    }
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        log("onAttach");

    }
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        log("onCreate");
    }
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        log("onCreateView");
        str = getArguments().getString("string");
        View v = inflater.inflate(R.layout.fragment_simple, container,false);
        TextView text = (TextView) v.findViewById(R.id.textview);
        text.setText(str);
        return v;
    }
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        log("onActivityCreated");
    }
    @Override
    public void onStart() {
        super.onStart();
        log("onStart");
    }
    @Override
    public void onResume() {
        super.onResume();
        log("onResume");
    }
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        log("onSaveInstanceState");
    }
    @Override
    public void onPause() {
        super.onPause();
        log("onPause");
    }
    @Override
    public void onStop() {
        super.onStop();
        log("onStop");
    }
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        log("onDestroyView");
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        log("onDestroy");
    }
    @Override
    public void onDetach() {
        super.onDetach();
        log("onDetach");
    }
    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        log("isHidden:" + hidden);
    }
    private void log(String s) {
        Log.v("tag","Fragment"+num +" -- " + s);
    }
}

布局:
activity_simple.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </FrameLayout>
</LinearLayout>

fragment_simple.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/textview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:textSize="20sp" />
</RelativeLayout>

启动Activity时,生命周期函数调用如下:


1.png

当按锁屏键、 多任务键或者直接按桌面键进入桌面时,这种情况我暂且称之为Activity挂起状态 ,这种情况下生命周期函数调用如下:

2挂起.png

当Activity从后台返回(再次按锁屏键打开屏幕,或从多任务界面回到当前应用程序界面)时,这种情况暂且称为挂起-唤醒 状态。生命周期函数调用如下:
3挂起_唤醒.png

当Activity销毁时:


4销毁.png

当旋转屏幕时,Activity和Fragment会被销毁,然后再重建:


5旋转屏幕.png

注意,上面的场景是,我在Activity的生命周期函数中super调用部分之后在打印log的。

场景二

于是我又做了这样的实验,我将log打印语句放在super之前,我将Activity的代码改为这样(其他代码不变):
Activity2.java

public class Activity2 extends AppCompatActivity {
    FragmentManager fragmentManager;
    FrameLayout frameLayout;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //在super之前打印log
        log("onCreate");       
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple);
        frameLayout = (FrameLayout) findViewById(R.id.container);
        fragmentManager = getSupportFragmentManager();
        if (savedInstanceState == null) {
            fragmentManager.beginTransaction()
                    .add(R.id.container,SimpleFragment1.getInstance("fragment") , "fragment")
                    .commit();
        }
    }

    @Override
    protected void onStart() {
        log("onStart");
        super.onStart();
        frameLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }
    @Override
    protected void onResume() {
        log("onResume");
        super.onResume();
    }
   @Override
    protected void onPause() {
        log("onPause");
        super.onPause();
    }
    @Override
    protected void onStop() {
        log("onStop");
        super.onStop();
    }
    @Override
    protected void onDestroy() {
        log("onDestroy");
        super.onDestroy();
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        log("onSaveInstanceState");
        super.onSaveInstanceState(outState);

    }
    private void log(String s) {
        Log.i("tag", "Activity2 -- " + s);
    }
}

Activity创建时,生命周期函数调用如下:

6创建.png

Activity挂起时:

7挂起.png

注意:与场景一不同,场景一是先打印了Fragment的生命周期函数,再打印了对应Activity的生命周期函数。在场景二下,是先打印了Activity的onPause再打印Fragment的onPauseonSaveInstanceStateonStop都是先打印了Activity再打印Fragment的。

说明Activity中的这个super.onXXXX从一定程度上与Fragment的生命周期相关。后面继续分析此处

先看在场景二下,Activity的挂起-唤醒状态

8挂起_唤醒.png

Activity的销毁:


9销毁.png

旋转屏幕:


10旋转屏幕.png

可以看到,在场景二下,logcat中打印的消息告诉我们,每个生命周期阶段,都是Activity的生命周期函数先执行,然后再执行Fragment的。

Activity生命周期中的super.onXXX与Fragment的关系分析

以Activity1中onCreatesuper.onCreate(savedInstanceState)为例分析:
因为我的Activity1继承自AppCompatActivity,AppCompatActivity的onCreate如下:

@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        final AppCompatDelegate delegate = getDelegate();
        delegate.installViewFactory();
        delegate.onCreate(savedInstanceState);
        if (delegate.applyDayNight() && mThemeId != 0) {
            // If DayNight has been applied, we need to re-apply the theme for
            // the changes to take effect. On API 23+, we should bypass
            // setTheme(), which will no-op if the theme ID is identical to the
            // current theme ID.
            if (Build.VERSION.SDK_INT >= 23) {
                onApplyThemeResource(getTheme(), mThemeId, false);
            } else {
                setTheme(mThemeId);
            }
        }
        super.onCreate(savedInstanceState);
    }

在最后又调用了super.onCreate(savedInstanceState),而AppCompatActivity是继承自FragmentActivity的,所以可以看出与Fragment一定存在某种联系。

FragmentActivity的onCreate

protected void onCreate(@Nullable Bundle savedInstanceState) {
        mFragments.attachHost(null /*parent*/);
        super.onCreate(savedInstanceState);
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            mFragments.restoreLoaderNonConfig(nc.loaders);
        }
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);

            // Check if there are any pending onActivityResult calls to descendent Fragments.
            if (savedInstanceState.containsKey(NEXT_CANDIDATE_REQUEST_INDEX_TAG)) {
                mNextCandidateRequestIndex =
                        savedInstanceState.getInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG);
                int[] requestCodes = savedInstanceState.getIntArray(ALLOCATED_REQUEST_INDICIES_TAG);
                String[] fragmentWhos = savedInstanceState.getStringArray(REQUEST_FRAGMENT_WHO_TAG);
                if (requestCodes == null || fragmentWhos == null ||
                            requestCodes.length != fragmentWhos.length) {
                    Log.w(TAG, "Invalid requestCode mapping in savedInstanceState.");
                } else {
                    mPendingFragmentActivityResults = new SparseArrayCompat<>(requestCodes.length);
                    for (int i = 0; i < requestCodes.length; i++) {
                        mPendingFragmentActivityResults.put(requestCodes[i], fragmentWhos[i]);
                    }
                }
            }
        }
        if (mPendingFragmentActivityResults == null) {
            mPendingFragmentActivityResults = new SparseArrayCompat<>();
            mNextCandidateRequestIndex = 0;
        }
        mFragments.dispatchCreate();
    }

最后一句mFragments.dispatchCreate();,mFragments是一个FragmentController 。 FragmentController是Activity中所有Fragment的生命周期管理者。其dispatchCreate如下:

 public void dispatchCreate() {
        mHost.mFragmentManager.dispatchCreate();
    }

mFragmentManager是一个FragmentManagerImpl类的实例,FragmentManagerImpl继承自FragmentManager类。这里我们把mFragmentManager看成是Fragment的存放容器就可以了。

dispatchCreate()的实现如下:

 public void dispatchCreate() {
        mStateSaved = false;
        mExecutingActions = true;
        moveToState(Fragment.CREATED, false);
        mExecutingActions = false;
    }

moveToState()的实现如下,部分代码省略:

void moveToState(int newState, boolean always) {
        .......
        mCurState = newState;

        if (mActive != null) {
            boolean loadersRunning = false;
            // Must add them in the proper order. mActive fragments may be out of order
            if (mAdded != null) {
                final int numAdded = mAdded.size();
                for (int i = 0; i < numAdded; i++) {
                    Fragment f = mAdded.get(i);
                    //标记处1
                    moveFragmentToExpectedState(f);
                    if (f.mLoaderManager != null) {
                        loadersRunning |= f.mLoaderManager.hasRunningLoaders();
                    }
                }
            }
            // Now iterate through all active fragments. These will include those that are removed
            // and detached.
            final int numActive = mActive.size();
            for (int i = 0; i < numActive; i++) {
                Fragment f = mActive.get(i);
                if (f != null && (f.mRemoving || f.mDetached) && !f.mIsNewlyAdded) {
                    //标记处2
                    moveFragmentToExpectedState(f);
                    if (f.mLoaderManager != null) {
                        loadersRunning |= f.mLoaderManager.hasRunningLoaders();
                    }
                }
            }
          .......
        }
    }

(在上面代码片段中我做了两个标记处,后面接着分析这两处)
moveToState中又调用了moveFragmentToExpectedState(),从函数名可知,实际做的就是将每个fragment都转移到各自对应的状态。
Fragment定义了如下几种状态:
static final int INITIALIZING = 0; // Not yet created.
static final int CREATED = 1; // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
static final int STOPPED = 3; // Fully created, not started.
static final int STARTED = 4; // Created and started, not resumed.
static final int RESUMED = 5; // Created started and resumed.
初始时Fragment是位于INITIALIZING 状态。

moveFragmentToExpectedState(Fragment f)函数:

void moveFragmentToExpectedState(Fragment f) {
        ....
        moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);

        if (f.mView != null) {
            // Move the view if it is out of order
            Fragment underFragment = findFragmentUnder(f);
            if (underFragment != null) {
                final View underView = underFragment.mView;
                // make sure this fragment is in the right order.
                final ViewGroup container = f.mContainer;
                int underIndex = container.indexOfChild(underView);
                int viewIndex = container.indexOfChild(f.mView);
                if (viewIndex < underIndex) {
                    container.removeViewAt(viewIndex);
                    container.addView(f.mView, underIndex);
                }
            }
           ...
          }
    }

其中调用了moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive)moveToState函数较长,该函数我把它称为关键函数吧,部分代码省略:

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.mAdded || f.mDetached) && newState > Fragment.CREATED) {
            newState = Fragment.CREATED;
        }
        .....
        if (f.mState < newState) {
            ....
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    ....
            //1.在这里调用了Fragment的onAttach()
                    f.onAttach(mHost.getContext());
                    ...
                    dispatchOnFragmentAttached(f, mHost.getContext(), false);

                    if (!f.mRetaining) {
            //2.在performCreate内部调用了Fragment的onCreate()
                        f.performCreate(f.mSavedFragmentState);
                        dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
                    } else {
                        f.restoreChildFragmentState(f.mSavedFragmentState);
            //*****注意:这里将Fragment的状态设置为CREATED
                        f.mState = Fragment.CREATED;
                    }
            f.mRetaining = false;
                    if (f.mFromLayout) {
                        //3.在performCreateView中调用了Fragment的onCreateView()
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), null, f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.mInnerView = f.mView;
                            if (Build.VERSION.SDK_INT >= 11) {
                                ViewCompat.setSaveFromParentEnabled(f.mView, false);
                            } else {
                                f.mView = NoSaveStateFrameLayout.wrap(f.mView);
                            }
                            if (f.mHidden) f.mView.setVisibility(View.GONE);
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                            dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
                        } else {
                            f.mInnerView = null;
                        }
                    }
                    ....
                case Fragment.CREATED:
                    if (newState > Fragment.CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                        ....
            //4.在performActivityCreated()中调用了Fragment的onActivityCreated()
                        f.performActivityCreated(f.mSavedFragmentState);
                        dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
                        if (f.mView != null) {
                            f.restoreViewState(f.mSavedFragmentState);
                        }
                        f.mSavedFragmentState = null;
                    }
                case Fragment.ACTIVITY_CREATED:
                    if (newState > Fragment.ACTIVITY_CREATED) {
                        f.mState = Fragment.STOPPED;
                    }
                case Fragment.STOPPED:
                    if (newState > Fragment.STOPPED) {
                        f.performStart();
                        dispatchOnFragmentStarted(f, false);
                    }
                case Fragment.STARTED:
                    if (newState > Fragment.STARTED) {
                        f.performResume();
                        dispatchOnFragmentResumed(f, false);
                        f.mSavedFragmentState = null;
                        f.mSavedViewState = null;
                    }
            }
        } else if (f.mState > newState) {
            switch (f.mState) {
                case Fragment.RESUMED:
                    if (newState < Fragment.RESUMED) {
                        f.performPause();
                        dispatchOnFragmentPaused(f, false);
                    }
                case Fragment.STARTED:
                    if (newState < Fragment.STARTED) {
                        f.performStop();
                        dispatchOnFragmentStopped(f, false);
                    }
                case Fragment.STOPPED:
                    if (newState < Fragment.STOPPED) {
                        f.performReallyStop();
                    }
                case Fragment.ACTIVITY_CREATED:
                    .....
                case Fragment.CREATED:
                    .....
            }
        }  
    }

该函数中就是对Fragment的各种不同的状态进行处理,一开始Fragment是处于INITIALIZING状态的,在INITIALIZING对应的case 语句中,相应的调用了Fragment的onAttach(),onCreate()onCreateView(),我在代码中也写了注释。在调用了onCreate之后,同时Fragment的状态会被设置为CREATED

还记得moveToState(int newState, boolean always)中的标记处一和标记处二吗,记不得就再回去看看。这两处标记处都是调用了关键函数moveToState。我们可以这么理解,标记处一的关键函数是对INITIALIZING状态的Fragment进行处理,当执行完标记处一的关键函数后,Fragment的状态被设置为CREATED,然后到标记处二,对CREATED状态的Fragment再进行处理。

下面我们分析关键函数中对于CREATED状态的case语句:

 case Fragment.CREATED:
                    if (newState > Fragment.CREATED) {            
                        ....
            //在performActivityCreated()中调用了Fragment的onActivityCreated()
                        f.performActivityCreated(f.mSavedFragmentState);
                        dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
                        if (f.mView != null) {
                            f.restoreViewState(f.mSavedFragmentState);
                        }
                        f.mSavedFragmentState = null;
                    }

performActivityCreated()函数中,调用了Fragment的onActivityCreated():

 void performActivityCreated(Bundle savedInstanceState) {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.noteStateNotSaved();
        }
        mState = ACTIVITY_CREATED;
        mCalled = false;
        onActivityCreated(savedInstanceState);
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onActivityCreated()");
        }
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchActivityCreated();
        }
    }

至此,Fragment的创建过程基本完毕,Fragment的创建时生命周期函数可以解释为:在INITIALIZING中执行了onAttach(),onCreate()onCreateView(),在CREATED中执行了onActivityCreated()

其他的Fragment生命周期函数也和上面分析的onCreate类似,其本质都是在关键函数中对各种状态进行处理并触发生命周期回调函数。

总结

实际上同阶段下Activity的生命周期函数是Fragment的生命周期函数入口,这里同阶段是指Activity的onCreate对应Fragment的onCreate,Activity的onResume对应Fragment的onResume之类的。

Activity的super.onXXXX中正是调用了Fragment的生命周期函数onXXXX。这也就解释了场景一和场景二中为什么在不同的地方打印log结果输出是不一样的。

关于Activity与Fragment的生命周期,github上还有一位大神画了这样一张图,地址在这里:https://github.com/xxv/android-lifecycle

其实我还有一点没理解,在场景一中,由于我log语句是写在super之后的,为啥是Activity1的onResume先执行,再执行Fragment1的onResume?如果有知道的朋友请告诉我,谢谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容