说说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()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,002评论 6 509
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,777评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,341评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,085评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,110评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,868评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,528评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,422评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,938评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,067评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,199评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,877评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,540评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,079评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,192评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,514评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,190评论 2 357