一:taskAffinity 属性介绍
taskAffinity 是用来指示Activity属于哪一个Task,前提是Activity的launchMod是否设置了SingleTask或者Flag_ACTIVITY_NEW_TASK
默认情况下,在一个App中的所有Activity都有一样的taskAffinity,同属在一个Task中,但是我们也可以设置不同的taskAffinity,也可以在不同的App中,设置相同的taskAffinity,以达到不同app的Activity共用同一个Task的目的。
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实例,并放入任务栈中。
SingleTop栈顶模式
如果在任务栈的栈顶正好存有该Activity的实例,则会通过调用onNewIntent方法进行重用,否则就会同Standard标准模式一样,创建新的实例并放入栈顶。当且仅当启动的Activity和上一个Activity一致的时候才会通过调用onNewIntent()方法重用Activity,使用场景: 资讯阅读类App的内容界面。
singleTask 单一任务模式
该启动模式专门用于解决上面SingleTop的另外一种情况,只要栈中已经存在的该Activity的实例,就会直接调用OnNewIntent()方法来实现重用实例,重用时候直接让Activity实例回到栈顶,并且移除之前它上面的所有Activity实例。如果栈内不存在该实例,则会重新创建,使用场景: 浏览器的主页面或者大部分App的主界面。
singleInstance 启动模式
在一个新栈中创建Activity实例,并让多个应用共享栈中的该Activity实例,一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活调用该Activity时都会重用栈中的实例,值得注意的是,singleInstance不要用于中间页面,如果用于中间页面,跳转会出现很难受的问题。
三:Intent标签
我们一般在AndroidManifest.xml中设置 android:launchMode 启动模式,那么还有其它方式来设置启动模式吗?下面我们通过Intent标签来讲讲。
在Android中,除了通过配置文件来设置启动模式,我们还可以在代码中通过设置flag来设置启动模式。
Intent.setFlag(int flags);
- FLAG_ACTIVITY_NEW_TASK 该标识会使新启动的Activity独立创建一个TASK
- FLAG_ACTIVITY_CLEAR_TOP 该标识会检查启动的Activity是否存在于Task中,如果存在,则会清除其之上的Activity,使它获得焦点,并不重新实例化一个Activity,一般结合FLAG_ACTIVITY_NEW_TASK一起使用。
- FLAG_ACTIVITY_SINGLE_TOP 等同于在launcherMode属性中设置为SingleTop
四:Android启动流程和原理
Activity的启动流程如上图所示,Activity启动跳转都要经过System_server层,并经过其进行分发
A调用startActivty -----》 需要与AMS交互,此时需要获取到AMS代理对象的Binder,即上图中的AMP,
通过ActivityManagerNative.getDefault()获得,并调用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,...)
}
}}
1:startProcessLocked 方法首先调用Process.start("android.app.ActivityThread") 向Zygote发送一个启动流程的request,并告诉Zygote进程启动后,加载ActivityThread这个类的入口main函数,启动完成后,返回进程的pid,并向ams的handler发送一个延迟消息,为的是要求目标进程启动后,10s内需要向ams报告,否则ams会清除目标进程的相关信息
2: Process.start方法会调用startViaZygote()方法,该方法功能主要是 1:打开连接Zygote的socket,2:通过socket发送启动进程的参数信息
3:Zygote端主要逻辑在runOnce方法中,该方法内调用Zygote.forkAndSpecialize 方法创建子进程,创建完成之后,就分别在父子进程中做各自的事情
- 父进程通过handleParentProc(pid) 把子进程的pid通过socket发送给AMS
- 子进程通过调用handleChildProc函数,做一些通用的初始化工作,比如启用Binder机制,执行应用程序的入口函数
4: ActivityThread中的systemMain方法中,会创建一个ActivityThread对象,并调用thread.attach方法,为的是向AMS发送一个延迟消息
5: attach方法中,有个跨进程的调用,首先调用
IActivityManager mgr = ActivityManagerNative.getDefault();
获取到AMS的Binder代理对象,然后调用
mgr.attachApplication(mAppThread);
mAppThread是应用端的一个Binder对象ApplicationThread(ATP),这样AMS端就可以调用应用端了。
其中要明白AMS里面有两个栈,一个是Launch桌面栈,一个就是非桌面栈mFocusStack,此处的stack就是mFocusStack,它会将栈顶的ActivityRecord返回出来,我们的目标Activity早就放置在了栈顶,只是一直没有初始化,然后调用方法,来启动Activity,如果我们不启动另外一个进程,而是同一个进程,那么这第二大部分就不会存在了,而是直接调用realStartActivityLocked方法。
realStartActivityLocked(hr,app,true,true);
- realStartActivityLocked函数会调用app.thread.scheduleLaunchActivity(new Intent(r.intent),...);也就是通过之前注册的Binder对象ATP,调用scheduleLaunchActivity函数,在scheduleLaunchActivity函数里面:
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 函数主要是用来生成一个LoadedApk对象,它用来保存我们的apk信息,因为后面我们需要一个ClassLoader去加载Apk里面的Activity类,所以这里提前准备好。
3.handleLaunchActivity里面分为两个部分,一个是performLaunchActivity函数,一个是handleResumeActivity函数。
performLaunchActivity
Activity activity = mInstrumentation.newActivity(...);
//返回之前创建好的
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()