说说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的实例,则会通过调用onNewIntent方法进行重用,否则就会同Standard标准模式一样,创建新的实例并放入栈顶。当且仅当启动的Activity和上一个Activity一致的时候才会通过调用onNewIntent()方法重用Activity,使用场景: 资讯阅读类App的内容界面。

image.png

singleTask 单一任务模式

该启动模式专门用于解决上面SingleTop的另外一种情况,只要栈中已经存在的该Activity的实例,就会直接调用OnNewIntent()方法来实现重用实例,重用时候直接让Activity实例回到栈顶,并且移除之前它上面的所有Activity实例。如果栈内不存在该实例,则会重新创建,使用场景: 浏览器的主页面或者大部分App的主界面。

image.png

singleInstance 启动模式

在一个新栈中创建Activity实例,并让多个应用共享栈中的该Activity实例,一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活调用该Activity时都会重用栈中的实例,值得注意的是,singleInstance不要用于中间页面,如果用于中间页面,跳转会出现很难受的问题。

image.png

三: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启动流程和原理

image.png

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,...)
   }
}}
Activity启动流程

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);
  1. 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()

你可能感兴趣的:(说说Android App启动那些事)