從源碼分析Activity啟動時的生命周期

寫在前面的話

最近高產似母豬,每天都會寫點關于這個系列的總結。周一了,又開始忙碌的一天。項目趕趕趕,bug改改改,盼望著盼望著,終于下班了。突然想起小時候學過的一篇課文《和時間賽跑》,越來越覺得“光陰似箭,日月如梭”了。還以為是那個剛剛來到魔都的毛頭小子,突然間發現,現在已然變成了“猥瑣大叔”了。
雖然我并不猥瑣,雖然我并不是大叔。噢!又想起大學宿舍的猥瑣小哥了,那猥瑣的樣子.....
哎~不扯了,再扯就不用寫了。


1. 關于Activity的生命周期

自從開始入Android的坑的時候,就一直念叨著Activity啟動時先onCreate,再onStart,最后onResume。各個階段是啥含義具體不講了(我不會說我也不知道)。



但是,自從開始做Android就想過,這幾個方法究竟是什么時候調用的?又是誰去調用的他?以前呢,自己太菜了(雖然現在也是。。),根本沒有好好去看,最近有時間好好總結下關于這方面的知識。



在前面的Android的luncher啟動過程中已經講到,Activity啟動的時候會調用ApplicationThread的scheduleLaunchActivity方法。下面從這個地方開始分析整個過程。

2. scheduleLaunchActivity方法

這個方法其實不想說的,這里面只做了一個操作,就是通過Handler發送LAUNCH_ACTIVITY消息。

@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
        ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
        CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
        int procState, Bundle state, PersistableBundle persistentState,
        List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
        boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
    //對變量各種賦值
    ......
    //發送LAUNCH_ACTIVITY消息,并把數據傳入
    sendMessage(H.LAUNCH_ACTIVITY, r);
}

這里簡單看下這個H是何方神圣private class H extends Handler,好了看完了。這就夠了,這就是個Handler。


3. Handler處理LAUNCH_ACTIVITY消息

這里面處理也是很簡單的,調用了handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");方法。

public void handleMessage(Message msg) {
    if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
    switch (msg.what) {
        case LAUNCH_ACTIVITY: {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
            final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

            r.packageInfo = getPackageInfoNoCheck(
                    r.activityInfo.applicationInfo, r.compatInfo);
            //調用ActivityThread的handleLaunchActivity方法。
            handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        } break;
    }
    ......
}

4. handleLaunchActivity方法和performLaunchActivity方法

handleLaunchActivity又調用了performLaunchActivity方法去創建,并啟動Activity。

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    ......
    // Initialize before creating the activity
    WindowManagerGlobal.initialize();

    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        reportSizeConfigurations(r);
        Bundle oldState = r.state;
                //這里調用Activity的onResume方法
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
        ......
    } else {
        //Activity為null,則代表啟動出現問題,需要關閉
        try {
            ActivityManagerNative.getDefault()
                .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                        Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");

    ActivityInfo aInfo = r.activityInfo;
    //對各種信息的非空判斷以及為空的時候賦值
    ......

    Activity activity = null;
    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        //通過Instrumentation創建新的Activity
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
        ......
    }

    try {
        //創建Application
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        ......
        if (activity != null) {
            //創建Context
            Context appContext = createBaseContextForActivity(r, activity);
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (r.overrideConfig != null) {
                config.updateFrom(r.overrideConfig);
            }
            //這個Window是我們顯示的窗體
            Window window = null;
            if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                window = r.mPendingRemoveWindow;
                r.mPendingRemoveWindow = null;
                r.mPendingRemoveWindowManager = null;
            }
            //調用attach方法
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window);

            if (customIntent != null) {
                activity.mIntent = customIntent;
            }
            r.lastNonConfigurationInstances = null;
            activity.mStartedActivity = false;
            int theme = r.activityInfo.getThemeResource();
            if (theme != 0) {
                activity.setTheme(theme);
            }

            activity.mCalled = false;
            //判斷是不是持久化的,可以理解為新的現場保存,查了下說是5.0及以上有的一種更加堅固的保存數據方式
            //true會調用onCreate(@Nullable Bundle savedInstanceState,@Nullable PersistableBundle persistentState)
            //false會調用onCreate(@Nullable Bundle savedInstanceState)
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            if (!activity.mCalled) {
                throw new SuperNotCalledException(
                    "Activity " + r.intent.getComponent().toShortString() +
                    " did not call through to super.onCreate()");
            }
            r.activity = activity;
            r.stopped = true;
            //這里會調用onStart方法
            if (!r.activity.mFinished) {
                activity.performStart();
                r.stopped = false;
            }
            //調用onRestoreInstanceState方法,當然這個是在re-initialized狀態下,即重新初始化
            if (!r.activity.mFinished) {
                if (r.isPersistable()) {
                    if (r.state != null || r.persistentState != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                r.persistentState);
                    }
                } else if (r.state != null) {
                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                }
            }
            //onPostCreate這個會在程序完全運行起來調用,onStart以后。好像很少用
            if (!r.activity.mFinished) {
                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state,
                            r.persistentState);
                } else {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onPostCreate()");
                }
            }
        }
        r.paused = true;

        mActivities.put(r.token, r);

    } catch (SuperNotCalledException e) {
        throw e;

    } catch (Exception e) {
        ......
    }

    return activity;
}

Instrumentation.java
public Activity newActivity(ClassLoader cl, String className,
        Intent intent)
        throws InstantiationException, IllegalAccessException,
        ClassNotFoundException {
    //通過反射創建Activity
    return (Activity)cl.loadClass(className).newInstance();
}

從上面的分析來看,我們顯示使用Instrumentation.newActivity方法,通過反射創建一個Activity對象,接著會調用attach這個隱藏方法。之后根據是否是異常狀態恢復,去掉用onCreate方法,接著調用onStart方法,如果是在重新初始化的時候,則會調用callActivityOnRestoreInstanceState方法,最后在程序完全運行起來調調用Activity的callActivityOnPostCreate(這個很少用到啊)。


5. 還是先說下 onResume

在上面的代碼中,我們在執行完performLaunchActivity方法會執行handleResumeActivity方法。在這里,我們是執行了Activity的onResume方法。

final void handleResumeActivity(IBinder token,
        boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
    ActivityClientRecord r = mActivities.get(token);
    ......
    //執行onResume方法
    r = performResumeActivity(token, clearHide, reason);
    //onResume是activity與用戶能進行交互時被執行,用戶可以獲得activity的焦點,能夠與用戶交互
    if (r != null) {
        final Activity a = r.activity;
        final int forwardBit = isForward ?
                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
        
        boolean willBeVisible = !a.mStartedActivity;
        ......
        //通過ViewManager或者說WindowManager將要顯示的Activity顯示出來,這里以后應該會分析,不急不急
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            if (r.mPreserveWindow) {
                a.mWindowAdded = true;
                r.mPreserveWindow = false;
                ViewRootImpl impl = decor.getViewRootImpl();
                if (impl != null) {
                    impl.notifyChildRebuilt();
                }
            }
            if (a.mVisibleFromClient && !a.mWindowAdded) {
                a.mWindowAdded = true;
                wm.addView(decor, l);
            }
        } else if (!willBeVisible) {
            if (localLOGV) Slog.v(
                TAG, "Launch " + r + " mStartedActivity set");
            r.hideForNow = true;
        }
        ......
        if (!r.onlyLocalRequest) {
            r.nextIdle = mNewActivities;
            mNewActivities = r;
            Looper.myQueue().addIdleHandler(new Idler());
        }
        r.onlyLocalRequest = false;

        // Tell the activity manager we have resumed.
        if (reallyResume) {
            try {
                //通過AMS設置狀態
                ActivityManagerNative.getDefault().activityResumed(token);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }

    } else {
        //和啟動一樣,如果有問題則結束掉
        try {
            ActivityManagerNative.getDefault()
                .finishActivity(token, Activity.RESULT_CANCELED, null,
                        Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
}

6. 總結

咦?好像有點不對,如果是啟動新的Activity時,會調用上一個頁面的onStop方法啊?不對啊,看看怎么編下去吧。



7. 遲到的onStop

其實這個onStop調用時機我在上面的代碼也展示出來了,只不過沒有標明。就在這段代碼中:

Looper.myQueue().addIdleHandler(new Idler());

private class Idler implements MessageQueue.IdleHandler {
    @Override
    public final boolean queueIdle() {
        ActivityClientRecord a = mNewActivities;
        boolean stopProfiling = false;
        if (mBoundApplication != null && mProfiler.profileFd != null
                && mProfiler.autoStopProfiler) {
            stopProfiling = true;
        }
        if (a != null) {
            mNewActivities = null;
            IActivityManager am = ActivityManagerNative.getDefault();
            ActivityClientRecord prev;
            do {
                if (a.activity != null && !a.activity.mFinished) {
                    try {
                        //通過AMS調用activityIdle方法,最終會執行onStop方法
                        am.activityIdle(a.token, a.createdConfig, stopProfiling);
                        a.createdConfig = null;
                    } catch (RemoteException ex) {
                        throw ex.rethrowFromSystemServer();
                    }
                }
                prev = a;
                a = a.nextIdle;
                prev.nextIdle = null;
            } while (a != null);
        }
        ......
        return false;
    }
}
AMS:
@Override
public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
    final long origId = Binder.clearCallingIdentity();
    synchronized (this) {
        ActivityStack stack = ActivityRecord.getStackLocked(token);
        //調用StackSupervisor.activityIdleInternalLocked方法
        if (stack != null) {
            ActivityRecord r =
                    mStackSupervisor.activityIdleInternalLocked(token, false, config);
            if (stopProfiling) {
                if ((mProfileProc == r.app) && (mProfileFd != null)) {
                    try {
                        mProfileFd.close();
                    } catch (IOException e) {
                    }
                    clearProfilerLocked();
                }
            }
        }
    }
    Binder.restoreCallingIdentity(origId);
}
ActivityStackSupervisor.java
final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
        Configuration config) {
    ......

    for (int i = 0; i < NS; i++) {
        r = stops.get(i);
        final ActivityStack stack = r.task.stack;
        if (stack != null) {
            if (r.finishing) {
                stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);
            } else {
                //這里去真正stop Activity
                stack.stopActivityLocked(r);
            }
        }
    }
    ......

    return r;
}
ActivityStack.java
final void stopActivityLocked(ActivityRecord r) {
    if (r.app != null && r.app.thread != null) {
        adjustFocusedActivityLocked(r, "stopActivity");
        r.resumeKeyDispatchingLocked();
        try {
            ......
            //調用ApplicationThread的scheduleStopActivity方法,真正stop activity
            r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
            ......
        } catch (Exception e) {
            
        }
    }
}

上面一大部分就是關于onStop的大體過程,先是將Activity resume后將Idler(這個意思懶漢,無所事事的人)放到消息隊列中,當消息進行執行是,會執行其中的方法,并通過AMS調用activityIdle方法,AMS又調用ActivityStackSupervisor的activityIdleInternalLocked方法,而activityIdleInternalLocked方法又會調用ActivityStack的stopActivityLocked方法,又跑到ApplicationThread中的scheduleStopActivity方法去真正stop activity。下面簡單看下這個方法執行過程。


8. onStop真正執行過程

這里就簡單看下,無非還是通過Handler發送消息,在消息執行是調用ActivityThread的方法去執行stop。下面看下源碼:

public final void scheduleStopActivity(IBinder token, boolean showWindow,
        int configChanges) {
    int seq = getLifecycleSeq();
    if (DEBUG_ORDER) Slog.d(TAG, "stopActivity " + ActivityThread.this
            + " operation received seq: " + seq);
    sendMessage(
        showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE,
        token, 0, configChanges, seq);
}

private void handleStopActivity(IBinder token, boolean show, int configChanges, int seq) {
    ......
    //真正執行stop
    performStopActivityInner(r, info, show, true, "handleStopActivity");
    ......
}
private void performStopActivityInner(ActivityClientRecord r,
        StopInfo info, boolean keepShown, boolean saveState, String reason) {
        ......
        //如果有必要先執行pause方法
        performPauseActivityIfNeeded(r, reason);
        ......
        // Next have the activity save its current state and managed dialogs...
        if (!r.activity.mFinished && saveState) {
            if (r.state == null) {
                callCallActivityOnSaveInstanceState(r);
            }
        }

        if (!keepShown) {
            try {
                // 執行onStop方法
                r.activity.performStop(false /*preserveWindow*/);
            } catch (Exception e) {
                if (!mInstrumentation.onException(r.activity, e)) {
                    throw new RuntimeException(
                            "Unable to stop activity "
                            + r.intent.getComponent().toShortString()
                            + ": " + e.toString(), e);
                }
            }
            r.stopped = true;
        }
    }
}

整個流程大概就這樣,Activity的生命周期基本執行完成了。


9. 我還有話說

關于Instrumentation的各種方法,舉個例子來說,例如Instrumentation.callActivityOnCreate(activity, r.state)方法,這里會執行

public void callActivityOnCreate(Activity activity, Bundle icicle) {
        //創建前
        prePerformCreate(activity);
        //執行onCreate方法
        activity.performCreate(icicle);
        //創建完成
        postPerformCreate(activity);
}
Activity.java
final void performCreate(Bundle icicle) {
    restoreHasCurrentPermissionRequest(icicle);
    //真正執行onCreate
    onCreate(icicle);
    mActivityTransitionState.readState(icicle);
    performCreateCommon();
}

這個Instrumentation可以說是個小秘書,我可以替大老板執行任務,并且在執行任務前后悄悄的做點事情,這感覺就是代理模式啊!!


寫在后面的話

有完沒完了啊。好吧,真的結束了。后面還是會有分析,整理整理思路,趕明再出發。


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,530評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,407評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,981評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,759評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,204評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,415評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,955評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,650評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,892評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,675評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容