前言
面试的时候,大多会有人问:大体介绍下Activity的启动模式和他们的区别,对于入行1年左右的小伙伴可能随口而来,standard,singleTop,singleTask,singleInstance,然后巴拉巴拉的讲他们的区别,然后面试官又问,那如何不通过AndroidManifest让activity动态的切换启动模式打开activity呢?有些小伙伴可能就懵逼了,当然有些小伙伴照样知道可以通过Activity的flags去打开,然后面试官再问,请介绍几个除了activity的标识外的其他你用到的标识(心中一顿MMP)这个系列就为大家系统的把启动模式和flag的作用说一下。
正文
这篇文章主要是介绍启动模式,在介绍启动模式之前,先需要介绍ActivityStack。
然后AMS会把各种上面枚举状态的activity通过ActivityStack记录到TaskRecord(里面是多个ActivityRecord)里,ActivityRecord是记录Activity的所有信息用的,而TaskRecord其实就是真正意义上的栈,但是光光有一个TaskRecord是不能完成我们平时理解的activity栈。
等等,是不是有些乱?那好,我们分层把他们了解下
先看ActivityRecord
我们可以把它理解成activity的代号,比如你的身份证号码,我们通过身份证号码可以找到你,你也可以通过身份证号码去找到你所在的城市。总而言之,它可以代表activity,也能知道activity所在的栈是哪个。
再看TaskRecord
这个就是真正的一个栈,但是不是我们所理解的activity的栈,它只用来寸一个或多个ActivityRecord。我们可以把它理解为城市,这个城市里的人的身份证号码都是110开头的,它可以找到110开头的人,也能找到到底是哪个国家的。所以他会存一个或多个ActivityRecord。通过TaskRecord既能找到它所管辖的ActivityRecord也能知道它属于哪个ActivityStack
最后看ActivityStack
这个名字看起来像个栈,也就是我们所理解的activity的栈,其实不然,我们理解的activity栈只是一个数据建模,其实内部很复杂,我们可以把ActivityStack看成国家,它会有很多省份,可以通过省份管理好不同的人群。没错ActivityStack起到的是个管理作用,最终实现了我们所想象的activity栈,他有个mTaskHistory也就是身份证管理数据库,记录了所有没有被销毁的的栈。
关系如图所示
ok,了解上面这些个东西,我们就开始解密启动模式
启动模式
1、standard
我们先将Activity代码附上
public class Standard extends Activity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
}
public void openSelf(View v){
startActivity(new Intent(this,Standard.class));
}
}
布局
配置文件
然后点击打开自己连续点3次,由于是standard模式,所以任务栈中应该有图标启动的一个Standard 和三个自己点开的Standard
通过shell输入adb shell dumpsys activity activities
会看到一堆东西,我们过滤掉没用的,只剩下我们相关的
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
Stack #2:
Task id #946
* TaskRecord{575687d #946 A=shproject.com.shpdemo U=0 sz=4}
userId=0 effectiveUid=u0a257 mCallingUid=2000 mCallingPackage=null
affinity=shproject.com.shpdemo
intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=shproject.com.shpdemo/.test.activitys.Standard}
realActivity=shproject.com.shpdemo/.test.activitys.Standard
autoRemoveRecents=false isPersistable=true numFullscreen=4 taskType=0 mTaskToReturnTo=1
rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
Activities=[ActivityRecord{49cc79a u0 shproject.com.shpdemo/.test.activitys.Standard t946}, ActivityRecord{d453ea4 u0 shproject.com.shpdemo/.test.activitys.Standard t946}, ActivityRecord{8d14d72 u0 shproject.com.shpdemo/.test.activitys.Standard
t946}, ActivityRecord{afd2e6c u0 shproject.com.shpdemo/.test.activitys.Standard t946}]
askedCompatMode=false inRecents=true isAvailable=true
lastThumbnail=null lastThumbnailFile=/data/system/recent_images/946_task_thumbnail.png
stackId=2
hasBeenVisible=true mResizeable=false firstActiveTime=1512026726749 lastActiveTime=1512026726749 (inactive for 6s)
* Hist #3: ActivityRecord{afd2e6c u0 shproject.com.shpdemo/.test.activitys.Standard t946}
packageName=shproject.com.shpdemo processName=shproject.com.shpdemo
launchedFromUid=10257 launchedFromPackage=shproject.com.shpdemo userId=0
app=ProcessRecord{780880a 28979:shproject.com.shpdemo/u0a257}
Intent { cmp=shproject.com.shpdemo/.test.activitys.Standard }
frontOfTask=false task=TaskRecord{575687d #946 A=shproject.com.shpdemo U=0 sz=4}
taskAffinity=shproject.com.shpdemo
realActivity=shproject.com.shpdemo/.test.activitys.Standard
baseDir=/data/app/shproject.com.shpdemo-2/base.apk
dataDir=/data/user/0/shproject.com.shpdemo
stateNotNeeded=false componentSpecified=true mActivityType=0
compat={320dpi} labelRes=0x7f060021 icon=0x7f030000 theme=0x7f0800a3
config={1.0 460mcc1mnc zh_CN ldltr sw360dp w360dp h616dp 320dpi nrml long port finger -keyb/v/h -nav/h s.25 themeChanged=0 themeChangedFlags=0}
stackConfigOverride={1.0 ?mcc?mnc ?locale ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/? themeChanged=0 themeChangedFlags=0}
taskDescription: iconFilename=null label="null" color=ff3f51b5
launchFailed=false launchCount=0 lastLaunchTime=-7m2s663ms
haveState=false icicle=null
state=RESUMED stopped=false delayedResume=false finishing=false
keysPaused=false inHistory=true visible=true sleeping=false idle=true
fullscreen=true noDisplay=false immersive=false launchMode=0
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=APPLICATION_ACTIVITY_TYPE
waitingVisible=false nowVisible=true lastVisibleTime=-7m2s317ms
* Hist #2: ActivityRecord{8d14d72 u0 shproject.com.shpdemo/.test.activitys.Standard t946}
packageName=shproject.com.shpdemo processName=shproject.com.shpdemo
launchedFromUid=10257 launchedFromPackage=shproject.com.shpdemo userId=0
app=ProcessRecord{780880a 28979:shproject.com.shpdemo/u0a257}
Intent { cmp=shproject.com.shpdemo/.test.activitys.Standard }
frontOfTask=false task=TaskRecord{575687d #946 A=shproject.com.shpdemo U=0 sz=4}
taskAffinity=shproject.com.shpdemo
realActivity=shproject.com.shpdemo/.test.activitys.Standard
baseDir=/data/app/shproject.com.shpdemo-2/base.apk
dataDir=/data/user/0/shproject.com.shpdemo
stateNotNeeded=false componentSpecified=true mActivityType=0
compat={320dpi} labelRes=0x7f060021 icon=0x7f030000 theme=0x7f0800a3
config={1.0 460mcc1mnc zh_CN ldltr sw360dp w360dp h616dp 320dpi nrml long port finger -keyb/v/h -nav/h s.25 themeChanged=0 themeChangedFlags=0}
stackConfigOverride={1.0 ?mcc?mnc ?locale ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/? themeChanged=0 themeChangedFlags=0}
taskDescription: iconFilename=null label="null" color=ff3f51b5
launchFailed=false launchCount=0 lastLaunchTime=-7m3s367ms
haveState=true icicle=Bundle[mParcelledData.dataSize=196]
state=STOPPED stopped=true delayedResume=false finishing=false
keysPaused=false inHistory=true visible=false sleeping=false idle=true
fullscreen=true noDisplay=false immersive=false launchMode=0
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=APPLICATION_ACTIVITY_TYPE
waitingVisible=false nowVisible=false lastVisibleTime=-7m3s18ms
* Hist #1: ActivityRecord{d453ea4 u0 shproject.com.shpdemo/.test.activitys.Standard t946}
packageName=shproject.com.shpdemo processName=shproject.com.shpdemo
launchedFromUid=10257 launchedFromPackage=shproject.com.shpdemo userId=0
app=ProcessRecord{780880a 28979:shproject.com.shpdemo/u0a257}
Intent { cmp=shproject.com.shpdemo/.test.activitys.Standard }
frontOfTask=false task=TaskRecord{575687d #946 A=shproject.com.shpdemo U=0 sz=4}
taskAffinity=shproject.com.shpdemo
realActivity=shproject.com.shpdemo/.test.activitys.Standard
baseDir=/data/app/shproject.com.shpdemo-2/base.apk
dataDir=/data/user/0/shproject.com.shpdemo
stateNotNeeded=false componentSpecified=true mActivityType=0
compat={320dpi} labelRes=0x7f060021 icon=0x7f030000 theme=0x7f0800a3
config={1.0 460mcc1mnc zh_CN ldltr sw360dp w360dp h616dp 320dpi nrml long port finger -keyb/v/h -nav/h s.25 themeChanged=0 themeChangedFlags=0}
stackConfigOverride={1.0 ?mcc?mnc ?locale ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/? themeChanged=0 themeChangedFlags=0}
taskDescription: iconFilename=null label="null" color=ff3f51b5
launchFailed=false launchCount=0 lastLaunchTime=-7m4s219ms
haveState=true icicle=Bundle[mParcelledData.dataSize=196]
state=STOPPED stopped=true delayedResume=false finishing=false
keysPaused=false inHistory=true visible=false sleeping=false idle=true
fullscreen=true noDisplay=false immersive=false launchMode=0
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=APPLICATION_ACTIVITY_TYPE
waitingVisible=false nowVisible=false lastVisibleTime=-7m3s787ms
* Hist #0: ActivityRecord{49cc79a u0 shproject.com.shpdemo/.test.activitys.Standard t946}
packageName=shproject.com.shpdemo processName=shproject.com.shpdemo
launchedFromUid=2000 launchedFromPackage=null userId=0
app=ProcessRecord{780880a 28979:shproject.com.shpdemo/u0a257}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=shproject.com.shpdemo/.test.activitys.Standard }
frontOfTask=true task=TaskRecord{575687d #946 A=shproject.com.shpdemo U=0 sz=4}
taskAffinity=shproject.com.shpdemo
realActivity=shproject.com.shpdemo/.test.activitys.Standard
baseDir=/data/app/shproject.com.shpdemo-2/base.apk
dataDir=/data/user/0/shproject.com.shpdemo
stateNotNeeded=false componentSpecified=true mActivityType=0
compat={320dpi} labelRes=0x7f060021 icon=0x7f030000 theme=0x7f0800a3
config={1.0 460mcc1mnc zh_CN ldltr sw360dp w360dp h616dp 320dpi nrml long port finger -keyb/v/h -nav/h s.25 themeChanged=0 themeChangedFlags=0}
stackConfigOverride={1.0 ?mcc?mnc ?locale ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/? themeChanged=0 themeChangedFlags=0}
taskDescription: iconFilename=null label="null" color=ff3f51b5
launchFailed=false launchCount=0 lastLaunchTime=-7m7s701ms
haveState=true icicle=Bundle[mParcelledData.dataSize=196]
state=STOPPED stopped=true delayedResume=false finishing=false
keysPaused=false inHistory=true visible=false sleeping=false idle=true
fullscreen=true noDisplay=false immersive=false launchMode=0
frozenBeforeDestroy=false forceNewConfig=false
mActivityType=APPLICATION_ACTIVITY_TYPE
waitingVisible=false nowVisible=false lastVisibleTime=-7m5s664ms
Running activities (most recent first):
TaskRecord{575687d #946 A=shproject.com.shpdemo U=0 sz=4}
Run #6: ActivityRecord{afd2e6c u0 shproject.com.shpdemo/.test.activitys.Standard t946}
Run #5: ActivityRecord{8d14d72 u0 shproject.com.shpdemo/.test.activitys.Standard t946}
Run #4: ActivityRecord{d453ea4 u0 shproject.com.shpdemo/.test.activitys.Standard t946}
Run #3: ActivityRecord{49cc79a u0 shproject.com.shpdemo/.test.activitys.Standard t946}
mResumedActivity: ActivityRecord{afd2e6c u0 shproject.com.shpdemo/.test.activitys.Standard t946}
mLastPausedActivity: ActivityRecord{afd2e6c u0 shproject.com.shpdemo/.test.activitys.Standard t946}
首先看 Running activities部分,这个最明显发现我们所有的activity是有四个的,并且都在 TaskRecord{575687d #946 A=shproject.com.shpdemo U=0 sz=4}的TaskRecord里面,再看上面的Hist ,这个是记录ActivityRecord的详细信息,包括包名,app的进程,Intent,taskAffinity等等数据,尤其是taskAffinity,我们后面会详细说明这个的用途。
通过这些数据我们发现standard的启动模式下的activity在新建打开时,会直接创建新的activity,并且会位于同一个TaskRecord里。
2、singleTop
据我们所知,这个是栈顶复用模式,位于栈定时,无论打开多少,都只会实例一个activity,于是我们通过两个方面测验这个是否正确。
1,singleTop打开singleTop,栈中永远只存在一个singleTop
2,singleTop打开Standard 通过Standard 打开singleTop,然后singleTop打开singleTop
首先实验1
代码如下
SingleTop.java
public class SingleTop extends Activity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
}
public void openSelf(View v){
startActivity(new Intent(this,SingleTop.class));
}
public void openStandard(View v){
startActivity(new Intent(this,Standard.class));
}
}
test_activity.xml
Standard.java
public class Standard extends Activity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_standard_activity);
}
public void openTop(View v){
startActivity(new Intent(this,SingleTop.class));
}
}
test_standard_activity.xml
AndroidManifest.xml
首先来看实验一,我运行完毕后连点三次打开自己
然后执行shell,这次把activityRecord去掉只留自己的runingActivity
Running activities (most recent first):
TaskRecord{644a128 #948 A=shproject.com.shpdemo U=0 sz=1}
Run #3: ActivityRecord{3938d53 u0 shproject.com.shpdemo/.test.activitys.SingleTop t948}
TaskRecord{5a4a4be #916 A=com.join.android.app.mgsim.wufun U=0 sz=4}
没错,只有一个,而且我点了半天感觉和没点似的,这个就是singleTop的特性了,当位于栈顶时,再次打开该activity时,该activity的生命周期不会执行onCreate,onStart,但是会执行onNewIntent,附上代码和效果
public class SingleTop extends Activity {
private static final String TAG="SingleTop";
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
Log.e(TAG,"onCreate");
}
@Override
protected void onStart() {
super.onStart();
Log.e(TAG,"onStart");
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e(TAG,"onNewIntent");
}
public void openSelf(View v){
startActivity(new Intent(this,SingleTop.class));
}
public void openStandard(View v){
startActivity(new Intent(this,Standard.class));
}
}
ok我们开始试验2
执行shell后得到如下效果
Running activities (most recent first):
TaskRecord{bc97677 #949 A=shproject.com.shpdemo U=0 sz=3}
Run #5: ActivityRecord{76ff3aa u0 shproject.com.shpdemo/.test.activitys.SingleTop t949}
Run #4: ActivityRecord{9072c52 u0 shproject.com.shpdemo/.test.activitys.Standard t949}
Run #3: ActivityRecord{35a3b91 u0 shproject.com.shpdemo/.test.activitys.SingleTop t949}
也就是说当SingleTop 位于栈顶时,打开SingleTop 不会实例新的activity,会执行当前实例的onNewIntent,当位于非栈顶时,该会在同一个TaskRecord实例新的activity
3、singleTask
栈内复用模式,这个特性很多,首先需要查看栈是否存在,若不存在创建新的栈,并向栈中压入activity,若栈存在,则在栈中寻找activity,若activity存在则将该activity置于栈顶(由于默认具备cleartop效果,该activity之上的activity清除),若activity不存在,则压入。
这里创建3个实验
1,栈A里的standard,启动栈BsingleTask,查看是否多出栈,每个栈中的activity
2,栈A里的singleTask,启动,栈Astandard,再通过栈Astandard启动栈AsingleTask,查看是否只有一个栈,并且只剩下singleTask
3,栈A里的standard,启动栈BsingleTask,在栈BsingleTask启动standard,然后在启动BsingleTask然后分别查看变化
这里需要引入一个新的属性TaskAffinity
这个是指定栈的名字,设置方法很简单,只需要在AndroidManifest相应的activity指定TaskAffinity属性即可,代码如下
我们把栈名设置为shproject.com.shpdemo.t1,执行看下效果
Running activities (most recent first):
TaskRecord{7bc3dc2 #952 A=shproject.com.shpdemo.t1 U=0 sz=1}
Run #3: ActivityRecord{feac7a2 u0 shproject.com.shpdemo/.test.activitys.SingleTask t952}
可以看到TaskRecord后面的A=shproject.com.shpdemo.t1已经变成我们指定的名字,ok,下面开始试验1
老规矩,附代码
SingleTask.java
public class SingleTask extends Activity {
private static final String TAG="SingleTask";
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_singletask_activity);
Log.e(TAG,"onCreate");
}
@Override
protected void onStart() {
super.onStart();
Log.e(TAG,"onStart");
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e(TAG,"onNewIntent");
}
public void openSelf(View v){
startActivity(new Intent(this,SingleTask.class));
}
public void openStandard(View v){
startActivity(new Intent(this,Standard.class));
}
}
Standard .java
public class Standard extends Activity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_standard_activity);
}
public void openSingleTask(View v){
startActivity(new Intent(this,SingleTask.class));
}
}
AndroidManifest.xml
android:screenOrientation="portrait">
先打开Standard,然后打开SingleTask,结果如下
TaskRecord{c544a43 #954 A=shproject.com.shpdemo.t1 U=0 sz=1}
Run #4: ActivityRecord{b95d3ea u0 shproject.com.shpdemo/.test.activitys.SingleTask t954}
TaskRecord{b80d9f9 #953 A=shproject.com.shpdemo U=0 sz=1}
Run #3: ActivityRecord{5e18b9c u0 shproject.com.shpdemo/.test.activitys.Standard t953}
明显可以看到TaskRecord存在两个,一个是包名,一个是我们设置的栈的名字。
这个时候我们开始试验3,启动Standard 看看
TaskRecord{c544a43 #954 A=shproject.com.shpdemo.t1 U=0 sz=2}
Run #5: ActivityRecord{db79d9d u0 shproject.com.shpdemo/.test.activitys.Standard t954}
Run #4: ActivityRecord{b95d3ea u0 shproject.com.shpdemo/.test.activitys.SingleTask t954}
TaskRecord{b80d9f9 #953 A=shproject.com.shpdemo U=0 sz=1}
Run #3: ActivityRecord{5e18b9c u0 shproject.com.shpdemo/.test.activitys.Standard t953}
厉害了,发现我们没有指定任务的Standard 分别存在于t1和包名中,也就是说,当我们不指定栈名时,是默认添加至发起发开activity的栈中的,现在我们在打开SingleTask
Running activities (most recent first):
TaskRecord{c544a43 #954 A=shproject.com.shpdemo.t1 U=0 sz=1}
Run #4: ActivityRecord{b95d3ea u0 shproject.com.shpdemo/.test.activitys.SingleTask t954}
TaskRecord{b80d9f9 #953 A=shproject.com.shpdemo U=0 sz=1}
Run #3: ActivityRecord{5e18b9c u0 shproject.com.shpdemo/.test.activitys.Standard t953}
没错,这个时候我们指定的t1存在,并且在t1中找到SingleTask ,由于clearTop效果,将我们刚刚打卡的Standard 清除了。
ok,我们在进行试验2,将配置文件稍稍改动
android:screenOrientation="portrait">
然后打开SingleTask,结果如下
Running activities (most recent first):
TaskRecord{839b122 #955 A=shproject.com.shpdemo U=0 sz=2}
Run #5: ActivityRecord{944e8a4 u0 shproject.com.shpdemo/.test.activitys.SingleTask t955}
Run #4: ActivityRecord{9e8beef u0 shproject.com.shpdemo/.test.activitys.Standard t955}
这个时候,我们再打开Standard 结果变为
TaskRecord{839b122 #955 A=shproject.com.shpdemo U=0 sz=3}
Run #6: ActivityRecord{5f81b7b u0 shproject.com.shpdemo/.test.activitys.Standard t955}
Run #5: ActivityRecord{944e8a4 u0 shproject.com.shpdemo/.test.activitys.SingleTask t955}
Run #4: ActivityRecord{9e8beef u0 shproject.com.shpdemo/.test.activitys.Standard t955}
然后我们再打开SingleTask
Running activities (most recent first):
TaskRecord{839b122 #955 A=shproject.com.shpdemo U=0 sz=2}
Run #5: ActivityRecord{944e8a4 u0 shproject.com.shpdemo/.test.activitys.SingleTask t955}
Run #4: ActivityRecord{9e8beef u0 shproject.com.shpdemo/.test.activitys.Standard t955}
ok,想必大家看明白了,试验2如同实验3,只不过一个是在默认栈中,一个是在指定栈中,只是证明了singleTask的clearTop作用。
4、singleInstance
老样子,走起,这把就不附上详细代码了,配置如下,直接看实验
1,栈AStandard ,打开默认singleInstance,看栈情况,然后singleInstance打开栈BStandard ,看栈情况,然后栈BStandard打开singleInstance看栈情况
首先打开singleInstance
效果如下
Running activities (most recent first):
TaskRecord{379ffb2 #958 A=shproject.com.shpdemo U=0 sz=1}
Run #5: ActivityRecord{e5008b4 u0 shproject.com.shpdemo/.test.activitys.SingleInstance t958}
TaskRecord{75b0a80 #957 A=shproject.com.shpdemo U=0 sz=1}
Run #4: ActivityRecord{3996192 u0 shproject.com.shpdemo/.test.activitys.Standard t957}
可以明显看到,我们并未指定taskAffinity但是它自己新起了一个TaskRecord,而且名字属性都一样
执行打开指定栈的SingleTask,效果如下
Running activities (most recent first):
TaskRecord{b96670f #959 A=shproject.com.shpdemo.t1 U=0 sz=1}
Run #6: ActivityRecord{4afd9e6 u0 shproject.com.shpdemo/.test.activitys.SingleTask t959}
TaskRecord{379ffb2 #958 A=shproject.com.shpdemo U=0 sz=1}
Run #5: ActivityRecord{e5008b4 u0 shproject.com.shpdemo/.test.activitys.SingleInstance t958}
TaskRecord{75b0a80 #957 A=shproject.com.shpdemo U=0 sz=1}
Run #4: ActivityRecord{3996192 u0 shproject.com.shpdemo/.test.activitys.Standard t957}
好吧又多了一个栈,那从栈B的SingleTask 打开SingleInstance ,会不会有两个SingleInstance 呢?执行...
TaskRecord{379ffb2 #958 A=shproject.com.shpdemo U=0 sz=1}
Run #6: ActivityRecord{e5008b4 u0 shproject.com.shpdemo/.test.activitys.SingleInstance t958}
TaskRecord{b96670f #959 A=shproject.com.shpdemo.t1 U=0 sz=1}
Run #5: ActivityRecord{4afd9e6 u0 shproject.com.shpdemo/.test.activitys.SingleTask t959}
TaskRecord{75b0a80 #957 A=shproject.com.shpdemo U=0 sz=1}
Run #4: ActivityRecord{3996192 u0 shproject.com.shpdemo/.test.activitys.Standard t957}
我们发现,栈没有多,ActivityRecord也没有变,只是TaskRecord的顺序5和6调换了。
没错,这个就是singleInstance的特殊性,它会起一个新的栈,而且这个栈是特殊的栈,当我们不管从栈A还是栈B打开它的时候,它只会查看那个特殊的栈是否存在,存在就置换顺序,不存在才会创建。
小结
其实启动模式的执行过程大家都明白,但是真正使用起来可能如果不明白细节会有些坑,无论singleTop,还是singleTask首先去看是否是在同一个栈中启动,若是不同栈中启动,无论是不是栈顶,都会实例一个出来。singleInstance无论在哪个栈中启动只会存在一个。