框架層理解Activity生命週期(APP啟動過程)
1生命週期圖
2主要類圖呼叫
上面類圖關係中包含兩個程式,一個是應用程式程式,另一個是AMS程式,所以會涉及到程式間通訊,android程式間通訊用的是Binder通訊。
2.1客戶程式
ØActivityThread
可以看到該類有一個main方法,其實它是android一個應用程式的入口,每啟動一個應用程式,都會建立ActivityThread與之對應的例項,是應用程式的UI執行緒,Android程式啟動時會建立訊息迴圈。負責管理應用程式的生命週期,執行系統廣播及其ActivityManagerService請求執行的操作。屬於客戶端物件。
ØApplicationThread&ApplicatinThreadNative
ApplicationThread用來實現ActivityManagerService與ActivityThread之間的互動。在ActivityManagerService需要管理相關Application中的Activity的生命週期時,通過ApplicationThread與ActivityThread通訊,ApplicationThreadNative是ApplicationThread在客戶端的實現。
ØApplicationThreadProxy
ApplicationThreadProxy是ApplicationThread在伺服器端的代理。負責和伺服器端的ApplicatingThreadNative通訊。
AMS就是通過該代理與ActivityThread進行通訊的。
ØActivity& Intrumentation
Activity是應用程式真正做事情的類,每一個應用程式只有一個Instrumentation物件,每個Activity內都有一個對該物件的引用。Instrumentation可以理解為應用程式的管家,ActivityThread要建立或暫停某個Activity時,都需要通過Instrumentation。通俗的理解,Instrumentation與ActivityThread的區別,前者像是一個“家庭”裡的“管家”,後者是負責建立這個“家庭”,並負責對外打交道,比如接收AMS的通知等。
2.2 AMS程式
這裡說的AMS程式,實際指的是System_server程式,System_server程式起來的時候啟動AMS服務,AMS實際是ActivityManagerService的縮寫。
ØActivityManagerService
管理Activity的生命週期
ØActivityManagerNative
ActivityManagerService在伺服器端的實現,客戶端的請求呼叫ActivityManagerProxy後,通過IBinder,最終會在ActivityManagerNative中實現。ActivityManagerNative再通過呼叫ActivityManagerService的相關功能,以完成客戶端請求。
ØActivityManagerProxy
ActivityManagerService的在客戶端的代理。負責和伺服器端的ActivityManagerNative通訊。
ØActivityStack
Activity在AMS的棧管理,用來記錄已經啟動的Activity的先後關係,狀態資訊等。通過ActivityStack決定是否需要啟動新的程式。
ØActivityRecord
ActivityStack的管理物件,每個Activity在AMS對應一個ActivityRecord來記錄Activity的狀態以及其他的管理資訊。
ØTaskRecord
AMS抽象出來的一個“任務”的概念,是記錄ActivityRecord的棧,一個“Task”包含若干個ActivityRecord。AMS用TaskRecord確保Activity啟動和退出的順序。
ØProcessRecord
一個Apk檔案執行時會對應一個程式,ProcessRecord正是記錄一個程式中的相關資訊。
3startActivity流程
在Android系統中,應用程式是由Activity組成的,因此,應用程式的啟動過程實際上就是應用程式中的預設Activity的啟動過程。啟動Android應用程式中的Activity的兩種情景,第一,在android裝置螢幕中點選應用程式圖示的情景就會引發Android應用程式中的預設Activity的啟動,從而把應用程式啟動起來,這種啟動方式的特點是會啟動一個新的程式來載入相應的Activity。第二,應用程式內部啟動非預設Activity的過程的原始碼,這種非預設Activity一般是在原來的程式和任務中啟動的。在Android的Activity管理機制中,當退出Activity的時候,在某些情況下並沒有立即把該Activity殺死,而是將其暫時儲存起來,當第二次呼叫startActivity啟動該Activity的時候,就不需要再建立該Activity的例項,直接恢復Activity即可。
3.1呼叫流程圖
對使用者來講,啟動一個Activity有以下幾種方式:
Ø在應用程式中呼叫startActivity()啟動指定的Activity
Ø在Home程式中點選一個應用圖示,啟動新的Activity
Ø按“Back”鍵,結束當前Activity,自動啟動上一個Activity
Ø長按“Home”鍵,顯示當前列表中,從中選則一個啟動
對於AMS內部講,啟動一個Activity有三種方式,如上圖中的①②③分支:
①目標Activity的物件已經存在,那麼直接resume該Activity
②目標Activity所在的程式不存在,那麼需要建立程式,並在新的程式中啟動該Activity
③目標Activity所在程式已經存在,那麼直接在已存在程式中啟動該Activity
3.2在新的程式中啟動
以在Home程式中點選一個應用圖示,啟動MainActivity為例子,介紹如下。
時序圖如下圖:
以上時序圖包含35步驟呼叫,下面逐一講解:
3.2.1(1~4),Launcher中傳送startActivity請求
在Android系統中,應用程式是由Launcher啟動起來的,其實,Launcher本身也是一個應用程式,其它的應用程式安裝後,就會Launcher的介面上出現一個相應的圖示,點選這個圖示時,Launcher就會對應的應用程式啟動起來。
Launcher繼承與Activity,Activity類的有個成員變數mInstrumentation是,它的型別是Intrumentation,它用來監控應用程式和系統的互動。
Instrumentation.execStartActivity:
publicActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activitytarget, Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread)contextThread; …… try { intent.setAllowFds(false); intent.migrateExtraStreamToClipData(); int result = ActivityManagerNative.getDefault() .startActivity(whoThread, intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { } return null; } |
這裡的ActivityManagerNative.getDefault返回ActivityManagerService的遠端介面,即ActivityManagerProxy介面。
3.2.2(5-8)AMS接收客戶端startActivity請求
客戶端通過Binder呼叫,最終呼叫到ActivityStack.startActivityLocked:
final intstartActivityLocked(IApplicationThread caller, Intent intent, String resolvedType, ActivityInfo aInfo, IBinderresultTo, String resultWho, int requestCode, int callingPid, int callingUid, int startFlags, Bundleoptions, boolean componentSpecified, ActivityRecord[] outActivity){
ProcessRecord callerApp = null; if (caller != null) { callerApp = mService.getRecordForAppLocked(caller); if (callerApp != null) { callingPid = callerApp.pid; callingUid = callerApp.info.uid; } else { …… } } …. ActivityRecord sourceRecord = null; ActivityRecord resultRecord = null; …. int launchFlags = intent.getFlags(); …. if((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT)!= 0 && sourceRecord != null){ // Transfer the result target from the source activity to thenew // one being started, including any failures. ……. } …… ActivityRecord r = new ActivityRecord(mService, this, callerApp,callingUid, intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho, requestCode,componentSpecified); if (outActivity != null) { outActivity[0] = r; } …… err = startActivityUncheckedLocked(r, sourceRecord, startFlags, true, options); …… return err; } |
startActivityLock()主要做了一下幾件事:
①處理傳進來的引數caller,得到呼叫者的程式資訊,並儲存在callerApp變數中,這裡就是Launcher應用程式的程式資訊了。
②處理FLAG_ACTIVITY_FORWARD_RESULT標誌。該標誌的特殊作用,就是能跨Activity傳Result,比如A1->A2,A2帶該標誌啟動A3,那麼A3呼叫setResult,然後finish(),結果將直接返回到A1
③建立一個臨時的ActivityRecord物件,該物件只為了後面呼叫過程中的各種對比,不一定會最終加入到mHistory列表中。
④判斷mPendingActivityLaunches列表是否有等待的Activity要啟動,如果有先啟動等待的Activity
⑤呼叫startActivityUncheckedLocked()方法。此時要啟動的Activity已經通過檢驗,被人認為是一個正當的啟動請求。
3.2.3(9)建立新的Task
呼叫ActivityStack.startActivityUncheckedLocked()處理Task問題,因為這裡我們是新啟動一個apk,所以將建立新的Task,newTask=true,並呼叫ActivityStack.startActivityLoacked():
privatefinal void startActivityLocked(ActivityRecord r, booleannewTask, boolean doResume, boolean keepCurTransition) { …… if (!newTask) { ……. } } // Place a new activity at top of stack, so it is next tointeract // with the user. if (addPos < 0) { addPos = NH; } …… mHistory.add(addPos, r); r.putInHistory(); r.frontOfTask = newTask; …… if (doResume) { resumeTopActivityLocked(null); } } |
注意AtivityStack中有兩個startActivityLoacked()方法,這裡呼叫的是帶四個引數的,即startActivityLocked(ActivityRecord r, booleannewTask,boolean doResume, booleankeepCurTransition),其中,r為將要啟動的Activity,newTask=true,doResume=true,在這個方法中,將r放到mHistory的最後面doResume=true,所以呼叫resumeTopActivityLocked(null)。關於Task的概念比較複雜,這裡先不講解。
3.2.4:(10)執行mHistory中最後一個ActivityRecord
ActivityStack. resumeTopActivityLocked(null)
finalboolean resumeTopActivityLocked(ActivityRecord prev) { // Find the first activity that is not finishing. ActivityRecord next = topRunningActivityLocked(null); if (next == null) { // There are no more activities!Let's just startup the // Launcher... if (mMainStack) { return mService.startHomeActivityLocked(); } } next.delayedResume = false;
// If the top activity is the resumed one, nothing todo. if (mResumedActivity == next &&next.state == ActivityState.RESUMED) { // Make sure we have executed any pending transitions, sincethere // should be nothing left to do at this point. mService.mWindowManager.executeAppTransition(); mNoAnimActivities.clear(); return false; }
// If we are sleeping, and there is no resumed activity, and thetop // activity is paused, well that is the state we want. if ((mService.mSleeping || mService.mShuttingDown) && mLastPausedActivity == next&& next.state ==ActivityState.PAUSED) { // Make sure we have executed any pending transitions, sincethere // should be nothing left to do at this point. mService.mWindowManager.executeAppTransition(); mNoAnimActivities.clear(); returnfalse; }
// The activity may be waiting for stop, but that is nolonger // appropriate for it. mStoppingActivities.remove(next); mGoingToSleepActivities.remove(next); next.sleeping = false; mWaitingVisibleActivities.remove(next); …… if (mPausingActivity != null) { if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" +mPausingActivity); return false; } ….. // We need to start pausing the current activity so the topone // can be resumed... if (mResumedActivity != null) { if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to startpausing"); startPausingLocked(userLeaving, false); return true; } …….. } |
呼叫resumeTopActivityLocked(null)啟動真正的Activity。
①呼叫topRunningActivityLocked()方法取出當前正在執行的ActivityRecord物件
②判斷mHistory中是否有記錄,如果沒有就意味著還沒有啟動任何的Activity,需要首先呼叫mService.startHomeActivityLocked()方法啟動所謂的“主介面程式”。當然我們這裡mHistroy已經有記錄了。
③判斷正在執行的Activity是否和目標Activity一樣,如果一樣,則直接返回。
④判斷當前系統是否處於休眠漲停,如果是,則返回。這裡繼續往下執行。
⑤從mStoppingActivities、mWaitingVisibleActivities和mGoingToSleepActivities中刪除目標物件,因為接下來將要被啟動。
⑥判斷當前是否在暫停某個Activity,如果是則還不能執行。這裡mPausingActivity=null,所以繼續往下執行。
⑦判斷當前是否有Activity在執行,如果有則先需要暫停當前的Activity。因為我們是在Lancher中啟動mainActivity,所以當前mResumedActivity!=null,所有呼叫startPausingLocked(userLeaving, false);
3.2.5(11~16)暫停當前執行Activity
①呼叫ActivityStack.startPausingLocked()暫停當前Activity。
②判斷執行當前Activity的程式是否存在。在這裡 if (prev.app != null&& prev.app.thread !=null)為真。其中,prev.app為記錄啟動Lancher程式的ProcessRecord,prev.app.thread為Lancher程式的遠端呼叫介面IApplicationThead,所以可以呼叫prev.app.thread.schedulePauseActivity,到Lancher程式暫停指定Activity。
③在Lancher程式中訊息傳遞,呼叫ActivityThread.handlePauseActivity(),最終呼叫ActivityTHread.performPauseActivity暫停指定Activity。接著通過Binder通訊,通知AMS已經完成暫停ActivityManagerNative.getDefault().activityPaused(token).
3.2.6(17~20) AMS處理暫停Activity事情
在Launcher通過Binder程式間通訊機制通知AMS,它已經準備就緒進入Paused狀態,在ActivityStack.completePauseLocked()中完成暫停:
private final void completePauseLocked(){ ActivityRecord prev = mPausingActivity; if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
if (prev != null) { if (prev.finishing) { prev = finishCurrentActivityLocked(prev,FINISH_AFTER_VISIBLE); } else if (prev.app != null) { …… if (prev.configDestroy) { destroyActivityLocked(prev, true, false,"pause-config"); } else { mStoppingActivities.add(prev); if (mStoppingActivities.size() > 3) { // If we already have a few activities waiting to stop, // then give up on things going idle and start clearing // them out. if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcingidle"); scheduleIdleLocked(); } else { checkReadyForSleepLocked(); } } } else { if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping:" + prev); prev = null; } mPausingActivity = null; }
if (!mService.isSleeping()) { resumeTopActivityLocked(prev); } else { checkReadyForSleepLocked(); } …… } |
①給prev賦值mPausingActivity,即上一個被執行的Activity,即Launcer
②如果prev的finishing為true,說明上一個Activity已經完成,因此需要呼叫finishCurrentActivityLocked()執行相關操作。一般的流程不會為true,這個條件似乎只有記憶體回收的時候才會被執行。
③將mPausingActivity變數置為空
④呼叫resumeTopActivityLocked方法正式啟動目標Activity,即MainActivity
3.2.7:(21~23)正式啟動目標Activity
呼叫AcivityStack.resumeTopActivityLocked:
final booleanresumeTopActivityLocked(ActivityRecord prev) { ActivityRecord next = topRunningActivityLocked(null); …… if (mResumedActivity != null) { if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to startpausing"); startPausingLocked(userLeaving, false); return true; }
if (next.app != null &&next.app.thread != null) { …… } startSpecificActivityLocked(next, true, true); }
return true; } |
①該方法在3.2.4步驟中呼叫過,那時是因為mResumedActivity != null,有Activity正在執行,所以去執行了startPausingLocked暫停Laucher去了。這時候,mResumedActivity=null,所以繼續往下執行。
②判斷講要啟動的Activity的客戶程式是否存在,這裡next.app != null &&next.app.thread != null為false
③呼叫ActivityStack.startSpecificActivityLocked
private final voidstartSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running? ProcessRecord app =mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid); …… if (app != null && app.thread !=null) { …… realStartActivityLocked(r, app, andResume, checkConfig); return; }
mService.startProcessLocked(r.processName, r.info.applicationInfo,true, 0, "activity", r.intent.getComponent(), false); } |
④客戶程式不存在,app!= null && app.thread !=null為false,所以呼叫mService.startProcessLocked() fork一個新的程式。
3.2.8(24) fork一個新的程式
①AMS通過Socket通訊,向Zygote傳送一個建立程式請求,Zygote建立新程式。
②建立好程式後,呼叫ActivityThread.main()。到此,我們到了新了一個程式中,也是程式的入口出。
③呼叫ActivityThread.attach()開始新的應用程式,接著同過Binder通訊通知AMS,新的程式已經建立好了,可以開始新的程式了。
3.2.9(26~28) AMS準備執行目標Activity
目標程式啟動後,報告給AMS,自己已經啟動完畢可以啟動Activity了,這裡通過IPC呼叫AMS的attachApplication方法完成。
ActivityManagerService.attachApplication():
public final voidattachApplication(IApplicationThread thread) { synchronized (this) { int callingPid = Binder.getCallingPid(); final long origId = Binder.clearCallingIdentity(); attachApplicationLocked(thread,callingPid); Binder.restoreCallingIdentity(origId); } } |
①根據Binder.getCallingPid(),或得客戶程式pid,並呼叫attachApplicationLocked(IApplicationThreadthread,int pid)
②在attachApplicationLocked中,根據pid找到對應的ProcessRecord物件,如果找不到說明改pid客戶程式是一個沒經過AMS允許的程式。
private final booleanattachApplicationLocked(IApplicationThread thread, int pid) { ProcessRecord app; if (pid != MY_PID && pid>= 0) { synchronized (mPidsSelfLocked) { app = mPidsSelfLocked.get(pid); } } if (app == null) { …… returnfalse; }
// If this application record is still attached to aprevious // process, clean it up now. if (app.thread != null) { handleAppDiedLocked(app, true, true); } …… app.thread = thread; app.curAdj = app.setAdj = -100; app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; app.setSchedGroup =Process.THREAD_GROUP_BG_NONINTERACTIVE; app.forcingToForeground = null; app.foregroundServices = false; app.hasShownUi = false; app.debugging = false; …… ensurePackageDexOpt(app.instrumentationInfo != null ? app.instrumentationInfo.packageName : app.info.packageName); …… // See if the top visible activity is waiting to run in thisprocess... ActivityRecord hr =mMainStack.topRunningActivityLocked(null); if (hr != null && normalMode){ if (hr.app == null && app.info.uid== hr.info.applicationInfo.uid &&processName.equals(hr.processName)) { …… if (mMainStack.realStartActivityLocked(hr, app, true,true)) …… return true; } |
③為ProcessRecordapp物件內部變數賦值
④確保目標程式(APK)檔案已經被轉換為了odex檔案。Android中安裝程式是APK檔案,實際上是一個zip檔案。
⑤呼叫ActivityStack.realStartActivityLocked通知客戶程式執行指定Activity.
⑥呼叫ApplicationThread.scheduleLaunchActivity,啟動指定Activity。
3.2.10:(29~35)客戶程式啟動指定Activity
AMS通過IPC通行,通知客戶程式啟動指定Activity
①呼叫ApplicationThread.scheduleLaunchActivity
②經過Handler訊息傳動,呼叫ActivityThread.handleLaunchActivity()
③呼叫ActivityThread.performLaunchActivity()完成Activity的載入,並最終呼叫Activity生命週期的onCreate()方法
④performLaunchActivity返回,繼續呼叫ActivityThread.handleResumeActivity(),該方法內部又呼叫ActivityThread.performResumeActivity(),其內部僅僅呼叫了目標Activity的onResume()方法。到此Activity啟動完成。
⑤新增一個IdleHandler物件,因為在一般情況下,該步驟執行完畢後,Activity就會進入空閒狀態,所以就可以進行記憶體回收。
3.3在已有程式中啟動
在已有的程式中啟動Activity,也就是在一個應用程式中啟動內部Activity,其過程跟3.2小節大致一樣,這裡我們不會像3.2小節詳細分析每一步驟,我們只看差別的地方。這裡以啟動subActivity為例子。時序圖如下:
以上時序圖包含29步驟呼叫,下面逐一講解:
3.3.1(1~3)在MainActivity啟動Activity
這一步跟3.2.1小節一樣
3.3.2(4~7) AMS接收客戶端startActivity請求
這一步跟3.2.2小節一樣
3.3.3(8)不需要建立新的Task
呼叫ActivityStack.startActivityUncheckedLocked()處理Task問題,因為這裡我們是在已有應用中startActivity,也不設定標誌要在新的Task中啟動Activity,所以不建立新的Task,newTask=false,並呼叫
ActivityStack.startActivityLoacked():
privatefinal void startActivityLocked(ActivityRecord r, booleannewTask, boolean doResume, boolean keepCurTransition) { …… if (!newTask) { ……. } } // Place a new activity at top of stack, so it is next tointeract // with the user. if (addPos < 0) { addPos = NH; } …… mHistory.add(addPos, r); r.putInHistory(); r.frontOfTask = newTask; …… if (doResume) { resumeTopActivityLocked(null); } } |
注意AtivityStack中有兩個startActivityLoacked()方法,這裡呼叫的是帶四個引數的,即startActivityLocked(ActivityRecord r, booleannewTask,boolean doResume, booleankeepCurTransition),其中,r為將要啟動的Activity,newTask=false,doResume=true,在這個方法中,將r放到mHistory的最後面doResume=true,所以呼叫resumeTopActivityLocked(null)。
3.3.4(9)準備啟動mHistory中最後一個Activity
這一步跟3.2.4小節一樣
3.3.5(10~15)暫停MainActivity
這一步跟3.2.5小節一樣
3.3.6(16~19) AMS處理暫停MainActivity
這一步跟3.2.6小節一樣
3.3.7(20~22)正式啟動目標Activity
呼叫AcivityStack.resumeTopActivityLocked:
final booleanresumeTopActivityLocked(ActivityRecord prev) { ActivityRecord next = topRunningActivityLocked(null); …… if (mResumedActivity != null) { if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to startpausing"); startPausingLocked(userLeaving, false); return true; }
if (next.app != null &&next.app.thread != null) { …… } startSpecificActivityLocked(next, true, true); }
return true; } |
①呼叫startSpecificActivityLocked(next, true,true)
private final voidstartSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running? ProcessRecord app =mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid); …… if (app != null && app.thread !=null) { …… realStartActivityLocked(r, app, andResume, checkConfig); return; }
mService.startProcessLocked(r.processName, r.info.applicationInfo,true, 0, "activity", r.intent.getComponent(), false); } |
②subActivity程式已經存在,app != null&& app.thread !=null為true,所以呼叫realStartActivityLocked。
finalboolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, booleancheckConfig) throws RemoteException { ….. app.thread.scheduleLaunchActivity(new Intent(r.intent),r.appToken, System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration), r.compat, r.icicle, results, newIntents,!andResume, mService.isNextTransitionForward(), profileFile,profileFd, profileAutoStop); …… return true; } |
③呼叫ApplicationThread.scheduleLaunchActivity,啟動指定Activity。
3.3.8(23~29)客戶程式啟動指定Activity
這一步跟3.2.10是一樣的
3.4在已有的ActivityRecord中恢復指定Activity
經過上面3.2和3.3小節,現在對Activity的啟動流程應該是比較清晰的了,這一節就簡單的講下恢復Activity的流程。當ActivityRecord已經記錄有一個Activity,如果再次呼叫startActivity,並沒有標誌要建立Activity新的例項,那麼就可以直接恢復該Activity。
①啟動一個Activity,跟前面3.2節一樣,都需要暫停當前正在執行的Activity,暫停流程這裡就不講了,完成暫停後,呼叫ActivityStack.resumeTopActivityLocked()。
②因為AMS和ActivityTHread的IPC通訊,resumeTopActivityLocked會被反覆呼叫幾次,每次都會根據一些變數值的差異,走不同的流程。
finalboolean resumeTopActivityLocked(ActivityRecord prev) { // Find the first activity that is not finishing. ActivityRecord next = topRunningActivityLocked(null); …… if (mResumedActivity != null) { if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to startpausing"); startPausingLocked(userLeaving, false); return true; } …… if (next.app != null &&next.app.thread != null) { if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " +next); …… try { …… next.app.thread.scheduleResumeActivity(next.appToken, mService.isNextTransitionForward());
checkReadyForSleepLocked();
} catch (Exception e) { // Whoops, need to restart this activity! …… startSpecificActivityLocked(next, true, false); return true; } …… } else { …… return true; } |
③這裡,mResumedActivity = null,不走暫停流程。
④next.app != null &&next.app.thread != null為true,呼叫ApplicationThead.scheduleResumeActivity(),到客戶程式恢復指定Activity。
⑤經過訊息傳遞,呼叫ActivityTHread.handleResumeActivity()
⑥呼叫ActivityTHread.performResumeActivity()正在恢復Activity,接著回撥Activity的onResume()方法。
4 stop停止Activity
前面幾節彙總,A啟動到B時,需要先暫停A,然後再啟動B。什麼時候停止(stop)或者銷燬(Destory)呢?
4.1從暫停到停止全過程
4按Home鍵回到桌面
5按Back鍵回到上一個Activity
6長按Home鍵
相關文章
- Activity生命週期與啟動模式模式
- Activity的生命週期和啟動模式模式
- Activity生命週期與啟動模式筆記模式筆記
- Activity A 跳轉到 Activity B,生命週期的執行過程
- Activity生命週期深入理解2
- Activity生命週期
- Activity的生命週期和啟動模式詳解模式
- Android入門教程之Activity(生命週期,啟動...)Android
- Activity生命週期onDestroy
- Android Activity的生命週期和啟動模式詳解Android模式
- View生命週期與Activity生命週期的關係View
- App 啟動過程(含 Activity 啟動過程) | 安卓 offer 收割基APP安卓
- Android Activity生命週期Android
- Activity生命週期總結
- Android Activity是如何啟動的?Activity的生命週期是如何呼叫的?Android
- Activity 知識梳理(1) Activity生命週期
- iOS 基礎01--專案檔案、applecation、啟動過程、VC生命週期iOSAPP
- iOS-APP的啟動流程和生命週期iOSAPP
- 深入學習Activity生命週期
- [Android]Activity的生命週期Android
- activity的生命週期(總結)
- View和Activity的生命週期View
- Activity簡介及生命週期
- Activity啟動過程分析
- 理解VUE生命週期Vue
- Android 元件系列-----Activity生命週期Android元件
- Android Activity生命週期詳解Android
- 關於activity的生命週期1
- activity生命週期的onPause和onStop
- Android開發藝術(1)——Activity的生命週期和啟動模式Android模式
- Laravel框架生命週期Laravel框架
- iOS App生命週期iOSAPP
- App的生命週期APP
- 深入理解HarmonyOS UIAbility:生命週期、WindowStage與啟動模式探析UIWindows模式
- 軟體開發的生命週期過程
- Vue生命週期的理解Vue
- Activity橫豎屏切換生命週期
- Android全面解析之Activity生命週期Android