小记Activity启动模式和Flag(1)

前言

面试的时候,大多会有人问:大体介绍下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也就是身份证管理数据库,记录了所有没有被销毁的的栈。
关系如图所示


image.png

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));
    }
}

布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
<Button
    android:text="打开自己"
    android:onClick="openSelf"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

</LinearLayout>

配置文件

        <activity
            android:name=".test.activitys.Standard"
            android:launchMode="standard"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

然后点击打开自己连续点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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
<Button
    android:text="打开自己"
    android:onClick="openSelf"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
    <Button
        android:text="打开standard"
        android:onClick="openStandard"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:text="打开Top"
        android:onClick="openTop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

AndroidManifest.xml

    <activity
            android:name=".test.activitys.SingleTop"
            android:launchMode="singleTop"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".test.activitys.Standard"
            android:launchMode="standard"
            android:screenOrientation="portrait">

        </activity>

首先来看实验一,我运行完毕后连点三次打开自己
然后执行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));
    }
}
image.png

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属性即可,代码如下

        <activity
            android:name=".test.activitys.SingleTask"
            android:launchMode="singleTask"
            android:taskAffinity="shproject.com.shpdemo.t1"
            android:screenOrientation="portrait" />

我们把栈名设置为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

  <activity
            android:name=".test.activitys.Standard"
            android:launchMode="standard"<!--使用默认栈-->
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
   <activity
            android:name=".test.activitys.SingleTask"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"
            android:taskAffinity="shproject.com.shpdemo.t1">
        </activity>

先打开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,将配置文件稍稍改动

  <activity
            android:name=".test.activitys.Standard"
            android:launchMode="standard"<!--使用默认栈-->
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
   <activity
            android:name=".test.activitys.SingleTask"
            android:launchMode="singleTask"
            android:screenOrientation="portrait">
        </activity>

然后打开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

老样子,走起,这把就不附上详细代码了,配置如下,直接看实验

        <activity
            android:name=".test.activitys.SingleInstance"
            android:launchMode="singleInstance"

            android:screenOrientation="portrait" />
        <activity
            android:name=".test.activitys.SingleTask"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"
            android:taskAffinity="shproject.com.shpdemo.t1">

        </activity>
    

        <activity
            android:name=".test.activitys.Standard"
            android:launchMode="standard"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

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无论在哪个栈中启动只会存在一个。

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

推荐阅读更多精彩内容