說說Android App啟動那些事

一:taskAffinity 屬性介紹

taskAffinity 是用來指示Activity屬于哪一個Task,前提是Activity的launchMod是否設置了SingleTask或者Flag_ACTIVITY_NEW_TASK

默認情況下,在一個App中的所有Activity都有一樣的taskAffinity,同屬在一個Task中,但是我們也可以設置不同的taskAffinity,也可以在不同的App中,設置相同的taskAffinity,以達到不同app的Activity共用同一個Task的目的。

image.png

Default 啟動模式

依次打開FirstActivity->SecondActivity->ThirdActivity->SecondActivity,查看log信息:

11-08 20:38:54.890 13971-13971/com.xplee.task.task I/xplee: ***************分割線****************
11-08 20:38:54.890 13971-13971/com.xplee.task.task I/xplee: task id:22 FirstActivity onCreate
11-08 20:38:58.510 13971-13971/com.xplee.task.task I/xplee: task id:22 SecondActivity onCreate
11-08 20:39:01.190 13971-13971/com.xplee.task.task I/xplee: task id:22 ThirdActivity onCreate
11-08 20:39:28.600 13971-13971/com.xplee.task.task I/xplee: task id:22 SecondActivity onCreate

SingleTask啟動模式

依次打開FirstActivity->SecondActivity->ThirdActivity->SecondActivity,查看log信息:

11-08 20:49:04.920 17645-17645/com.xplee.task.task I/xplee: ***************分割線****************
11-08 20:49:04.920 17645-17645/com.xplee.task.task I/xplee: task id:24 FirstActivity onCreate
11-08 20:49:15.300 17645-17645/com.xplee.task.task I/xplee: task id:24 SecondActivity onCreate
11-08 20:49:17.170 17645-17645/com.xplee.task.task I/xplee: task id:24 ThirdActivity onCreate
11-08 20:49:22.710 17645-17645/com.xplee.task.task I/xplee: task id:24 SecondActivity onNewIntent
11-08 20:49:23.060 17645-17645/com.xplee.task.task I/xplee: task id:24 ThirdActivity onDestroy

singleTask & different taskAffinity

依次打開FirstActivity->SecondActivity->ThirdActivity->SecondActivity,查看log信息:

11-08 20:58:18.300 22445-22445/com.xplee.task.task I/xplee: ***************分割線****************
11-08 20:58:18.310 22445-22445/com.xplee.task.task I/xplee: task id:26 FirstActivity onCreate
11-08 20:58:29.340 22445-22445/com.xplee.task.task I/xplee: task id:27 SecondActivity onCreate
11-08 20:58:30.920 22445-22445/com.xplee.task.task I/xplee: task id:27 ThirdActivity onCreate
11-08 20:58:33.140 22445-22445/com.xplee.task.task I/xplee: task id:27 SecondActivity onNewIntent
11-08 20:58:33.480 22445-22445/com.xplee.task.task I/xplee: task id:27 ThirdActivity onDestroy

從上面日志可以看出,僅當設置Activity為SingleTask或者FLAG_ACTIVITY _NEW_TASK的時候,設置taskAffinity屬性才會起效。

二:Android啟動模式

Standard標準模式

默認的啟動模式,每次跳轉激活都會重新生成一個新的Activity實例,并放入任務棧中。

image.png

SingleTop棧頂模式

如果在任務棧的棧頂正好存有該Activity的實例,則會通過調(diào)用onNewIntent方法進行重用,否則就會同Standard標準模式一樣,創(chuàng)建新的實例并放入棧頂。當且僅當啟動的Activity和上一個Activity一致的時候才會通過調(diào)用onNewIntent()方法重用Activity,使用場景: 資訊閱讀類App的內(nèi)容界面。

image.png

singleTask 單一任務模式

該啟動模式專門用于解決上面SingleTop的另外一種情況,只要棧中已經(jīng)存在的該Activity的實例,就會直接調(diào)用OnNewIntent()方法來實現(xiàn)重用實例,重用時候直接讓Activity實例回到棧頂,并且移除之前它上面的所有Activity實例。如果棧內(nèi)不存在該實例,則會重新創(chuàng)建,使用場景: 瀏覽器的主頁面或者大部分App的主界面。

image.png

singleInstance 啟動模式

在一個新棧中創(chuàng)建Activity實例,并讓多個應用共享棧中的該Activity實例,一旦該模式的Activity實例已經(jīng)存在于某個棧中,任何應用再激活調(diào)用該Activity時都會重用棧中的實例,值得注意的是,singleInstance不要用于中間頁面,如果用于中間頁面,跳轉會出現(xiàn)很難受的問題。

image.png

三:Intent標簽

我們一般在AndroidManifest.xml中設置 android:launchMode 啟動模式,那么還有其它方式來設置啟動模式嗎?下面我們通過Intent標簽來講講。

在Android中,除了通過配置文件來設置啟動模式,我們還可以在代碼中通過設置flag來設置啟動模式。

Intent.setFlag(int flags);

  • FLAG_ACTIVITY_NEW_TASK 該標識會使新啟動的Activity獨立創(chuàng)建一個TASK
  • FLAG_ACTIVITY_CLEAR_TOP 該標識會檢查啟動的Activity是否存在于Task中,如果存在,則會清除其之上的Activity,使它獲得焦點,并不重新實例化一個Activity,一般結合FLAG_ACTIVITY_NEW_TASK一起使用。
  • FLAG_ACTIVITY_SINGLE_TOP 等同于在launcherMode屬性中設置為SingleTop

四:Android啟動流程和原理

image.png

Activity的啟動流程如上圖所示,Activity啟動跳轉都要經(jīng)過System_server層,并經(jīng)過其進行分發(fā)

A調(diào)用startActivty -----》 需要與AMS交互,此時需要獲取到AMS代理對象的Binder,即上圖中的AMP,

通過ActivityManagerNative.getDefault()獲得,并調(diào)用AMP的startActivity方法,通過mRemote.transact進行binder通信。

mRemote.transact(START_ACTIVITY_TRANSACTION,data,reply,0);
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags){
      switch(code){
   case START_ACTIVITY_TRANSACTION:{        startActivity(app,callingPackage,intent,...)
   }
}}
Activity啟動流程

1:startProcessLocked 方法首先調(diào)用Process.start("android.app.ActivityThread") 向Zygote發(fā)送一個啟動流程的request,并告訴Zygote進程啟動后,加載ActivityThread這個類的入口main函數(shù),啟動完成后,返回進程的pid,并向ams的handler發(fā)送一個延遲消息,為的是要求目標進程啟動后,10s內(nèi)需要向ams報告,否則ams會清除目標進程的相關信息

2: Process.start方法會調(diào)用startViaZygote()方法,該方法功能主要是 1:打開連接Zygote的socket,2:通過socket發(fā)送啟動進程的參數(shù)信息

3:Zygote端主要邏輯在runOnce方法中,該方法內(nèi)調(diào)用Zygote.forkAndSpecialize 方法創(chuàng)建子進程,創(chuàng)建完成之后,就分別在父子進程中做各自的事情

  • 父進程通過handleParentProc(pid) 把子進程的pid通過socket發(fā)送給AMS
  • 子進程通過調(diào)用handleChildProc函數(shù),做一些通用的初始化工作,比如啟用Binder機制,執(zhí)行應用程序的入口函數(shù)

4: ActivityThread中的systemMain方法中,會創(chuàng)建一個ActivityThread對象,并調(diào)用thread.attach方法,為的是向AMS發(fā)送一個延遲消息

5: attach方法中,有個跨進程的調(diào)用,首先調(diào)用

IActivityManager mgr = ActivityManagerNative.getDefault();

獲取到AMS的Binder代理對象,然后調(diào)用

mgr.attachApplication(mAppThread);

mAppThread是應用端的一個Binder對象ApplicationThread(ATP),這樣AMS端就可以調(diào)用應用端了。

其中要明白AMS里面有兩個棧,一個是Launch桌面棧,一個就是非桌面棧mFocusStack,此處的stack就是mFocusStack,它會將棧頂?shù)腁ctivityRecord返回出來,我們的目標Activity早就放置在了棧頂,只是一直沒有初始化,然后調(diào)用方法,來啟動Activity,如果我們不啟動另外一個進程,而是同一個進程,那么這第二大部分就不會存在了,而是直接調(diào)用realStartActivityLocked方法。

realStartActivityLocked(hr,app,true,true);
  1. realStartActivityLocked函數(shù)會調(diào)用app.thread.scheduleLaunchActivity(new Intent(r.intent),...);也就是通過之前注冊的Binder對象ATP,調(diào)用scheduleLaunchActivity函數(shù),在scheduleLaunchActivity函數(shù)里面:
ActivityClientRecord r = new ActivityClientRecord(); ... sendMessage(H.LAUNCH_ACTIVITY,r);

封裝了一個ActivityClientRecord消息,然后丟到主線程的Handler(mH)里。

2: 在主線程中

final ActivityClientRecord r = (ActivityClientRecord)msg.obj ;
r.packageInfo = getPackageInfoNoCheck(...); 
handleLaunchActivity(r,null);

getPackageInfoNoCheck 函數(shù)主要是用來生成一個LoadedApk對象,它用來保存我們的apk信息,因為后面我們需要一個ClassLoader去加載Apk里面的Activity類,所以這里提前準備好。

3.handleLaunchActivity里面分為兩個部分,一個是performLaunchActivity函數(shù),一個是handleResumeActivity函數(shù)。

performLaunchActivity

Activity activity = mInstrumentation.newActivity(...);
//返回之前創(chuàng)建好的
Application app = r.packageInfo.makeApplication(false,mInstrumentation);
//生成ContextImpl
Context appContext = createBaseContextForActivity(r,activity);
//給activity綁定上下文和一些初始化的工作,如createPhoneWindow
activity.attach(appContext,...);
mInstrumentation.callActivityOnCreate(activity,r.state); //生命周期的OnCreate
activity.performStart();    //生命周期的OnStart
return activity

handleResumeActivity:

r.activity.performResume()  -> mInstrumentation.callActivityOnResume(this); 
-> activity.onResume()
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容