Activity的启动模式

Activity的启动模式有4个,分别为standard、singleTop、singleTask、singleInstance。用户可以在AndroidManifest.xml中注册Activity时设置它的启动模式,例如:

  <activity android:name=".A"
            android:launchMode="singleTask"/>

下面我们来一起看一下这四种启动模式
一、standard(标准启动模式)
这是Activity的标准启动模式,也是Activity的默认启动模式。在这种模式下,Activity可以被多次实例化,即在同一个任务栈中可以存在多个Activity实例,每个实例都会处理一个Intent对象。如果ActivityA的启动模式为standard。并且已经有一个ActivityA被启动,在该ActivityA中启动一个新的ActivityA实例。那么栈中会有2个ActivityA。
standard
附上测试代码:
A.java

public class A extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);
        findViewById(R.id.a_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(A.this,A.class));
            }
        });
    }
}

AndroidManifest.xml

  <activity
            android:name=".A"
            android:taskAffinity="com.simple.myapplication.task1" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

执行 adb shell dumpsys activity 查看结果:

一开始只有一个ActivityA实例时:
 Stack #1:
   Task id #149
     TaskRecord{1a7d0c7e #149 A=com.simple.myapplication.task1 U=0 sz=1}
     Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000
mp=com.simple.myapplication/.A }
       Hist #0: ActivityRecord{3933a57 u0 com.simple.myapplication/.A t149}
         Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000
00 cmp=com.simple.myapplication/.A }
         ProcessRecord{e66022c 13440:com.simple.myapplication/u0a57}

   Running activities (most recent first):
     TaskRecord{1a7d0c7e #149 A=com.simple.myapplication.task1 U=0 sz=1}
       Run #0: ActivityRecord{3933a57 u0 com.simple.myapplication/.A t149}

   mResumedActivity: ActivityRecord{3933a57 u0 com.simple.myapplication/.A t149}

点击按钮继续启动一个ActiviyA 时:
 Stack #1:
   Task id #149
     TaskRecord{1a7d0c7e #149 A=com.simple.myapplication.task1 U=0 sz=2}
     Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000
mp=com.simple.myapplication/.A }
       Hist #1: ActivityRecord{102084f5 u0 com.simple.myapplication/.A t149}
         Intent { cmp=com.simple.myapplication/.A }
         ProcessRecord{e66022c 13440:com.simple.myapplication/u0a57}
       Hist #0: ActivityRecord{3933a57 u0 com.simple.myapplication/.A t149}
         Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000
00 cmp=com.simple.myapplication/.A }
         ProcessRecord{e66022c 13440:com.simple.myapplication/u0a57}

   Running activities (most recent first):
     TaskRecord{1a7d0c7e #149 A=com.simple.myapplication.task1 U=0 sz=2}
       Run #1: ActivityRecord{102084f5 u0 com.simple.myapplication/.A t149}
       Run #0: ActivityRecord{3933a57 u0 com.simple.myapplication/.A t149}

   mResumedActivity: ActivityRecord{102084f5 u0 com.simple.myapplication/.A t149}

二、singleTop(栈顶复用模式)
如果有一个以singleTop模式启动的Activity的实例已经存在于任务的栈顶,那么在启动这个Activity时,不会创建实例,而是重用位于栈顶的那个实例,并且会调用该实例的OnNewIntent()方法。
singleTop
附上测试代码:
B.java


public class B extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b);
        //启动Activity A
        findViewById(R.id.b_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(B.this,A.class));
            }
        });
    }
}

A.java


public class A extends AppCompatActivity {

    private static final String TAG = "A";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);
        //启动Activity A
        findViewById(R.id.a_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(A.this,A.class));
            }
        });
        Log.i(TAG, "onCreate: ");
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.i(TAG, "onNewIntent: ");
    }
}

AndroidManifest.xml

 <activity
            android:name=".A"
            android:launchMode="singleTop"
            android:taskAffinity="com.simple.myapplication.task1" >

        </activity>
        <activity
            android:name=".B"
            android:taskAffinity="com.simple.myapplication.task1" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

测试结果:

第一步:栈中存在B、A时
 Stack #1:
   Task id #151
     TaskRecord{22b8911f #151 A=com.simple.myapplication.task1 U=0 sz=2}
     Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000
mp=com.simple.myapplication/.B bnds=[556,958][704,1142] (has extras) }
       Hist #1: ActivityRecord{2c7a4235 u0 com.simple.myapplication/.A t151}
         Intent { cmp=com.simple.myapplication/.A }
         ProcessRecord{21c76c6c 25188:com.simple.myapplication/u0a57}
       Hist #0: ActivityRecord{826ed5f u0 com.simple.myapplication/.B t151}
         Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000
00 cmp=com.simple.myapplication/.B bnds=[556,958][704,1142] (has extras) }
         ProcessRecord{21c76c6c 25188:com.simple.myapplication/u0a57}

   Running activities (most recent first):
     TaskRecord{22b8911f #151 A=com.simple.myapplication.task1 U=0 sz=2}
       Run #1: ActivityRecord{2c7a4235 u0 com.simple.myapplication/.A t151}
       Run #0: ActivityRecord{826ed5f u0 com.simple.myapplication/.B t151}
第二步:点击A中的按钮,继续启动 ActivityA实例。
  Stack #1:
   Task id #151
     TaskRecord{22b8911f #151 A=com.simple.myapplication.task1 U=0 sz=2}
     Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000
mp=com.simple.myapplication/.B bnds=[556,958][704,1142] (has extras) }
       Hist #1: ActivityRecord{2c7a4235 u0 com.simple.myapplication/.A t151}
         Intent { cmp=com.simple.myapplication/.A }
         ProcessRecord{21c76c6c 25188:com.simple.myapplication/u0a57}
       Hist #0: ActivityRecord{826ed5f u0 com.simple.myapplication/.B t151}
         Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000
00 cmp=com.simple.myapplication/.B bnds=[556,958][704,1142] (has extras) }
         ProcessRecord{21c76c6c 25188:com.simple.myapplication/u0a57}

   Running activities (most recent first):
     TaskRecord{22b8911f #151 A=com.simple.myapplication.task1 U=0 sz=2}
       Run #1: ActivityRecord{2c7a4235 u0 com.simple.myapplication/.A t151}
       Run #0: ActivityRecord{826ed5f u0 com.simple.myapplication/.B t151}
    可以发现栈中并无变化。
    查看log信息:
    com.simple.myapplication I/A: onNewIntent: 
     执行了Activity A 的 OnNewInstance方法

三、singleTask(栈内复用模式)
如果一个Activity设置了该启动模式,那么一个任务栈中只能存在一个该Activity的实例。如果任务栈中存在该activity那么就不会创建新的activity,而是将这个已经存在的activity移至栈顶,并将位于该activity之上的别的activity销毁。并且和singleTop一样,会执行该activity的onNewIntent()函数。

singleTask

附上测试代码:

public class A extends AppCompatActivity {

    private static final String TAG = "A";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);
        //启动Activity B
        findViewById(R.id.a_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(A.this,B.class));
            }
        });
        Log.i(TAG, "onCreate: ");
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.i(TAG, "onNewIntent: ");
    }
}

public class B extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b);
        //启动Activity c
        findViewById(R.id.b_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(B.this,C.class));
            }
        });
    }
}

public class B extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b);
        //启动Activity c
        findViewById(R.id.b_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(B.this,C.class));
            }
        });
    }
}
public class C extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_c);
        findViewById(R.id.c_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(C.this,A.class));
            }
        });
    }
}

        <activity
            android:name=".A"
            android:launchMode="singleTask"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

测试流程: A启动B,B启动C ,C启动A 导致了BC出栈,最后栈中只剩下A,按返回键会返回桌面。

还有,假设现在存在2个栈,一个前台栈里面包含A,B和一个后台栈C,D
那么在B中启动D。将导致后台栈切换到前台。
这里写图片描述

另外我在测试中发现taskAffinity可以用来设置栈名称,一般情况下只有在启动模式为singleTask或者singleInstance和他配对使用时,启动的activity才会进入一个和这个名字相同的栈中。或者还有一种情况他会进入一个栈名称为taskAffiity设置的那个栈中,就是当启动他的activity的启动模式singleInstane时,他将创建一个栈名为taskAffinity的栈,用来压入新启动的activity。这是因为singleInstance的属性导致的他自身的栈中不能压入其他的Activity,所以会重新创建一个栈名为taskAffinity的栈用来存放启动的activity。

四、singleInstance(单实例模式)
这是一种加强的singleTask模式,它除了具有singleTask模式的属性外,还加强了一点,那就是该模式的Activity只能单独的位于一个任务栈中
singleInstance

附上测试代码:

public class A extends AppCompatActivity {

    private static final String TAG = "A";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);

        findViewById(R.id.a_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(A.this,B.class));
            }
        });
        Log.i(TAG, "onCreate: ");
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.i(TAG, "onNewIntent: ");
    }
}
public class B extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b);

        findViewById(R.id.b_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(B.this,D.class));
            }
        });
    }
}

        <activity
            android:name=".A"
            android:taskAffinity="com.simple.myapplicaiton.task1"
            android:launchMode="standard"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".B"
            android:taskAffinity="com.simple.myapplicaiton.task1"
            android:launchMode="singleInstance"
            >
        </activity>

最终导致栈中的信息为:

    Task id #238
      TaskRecord{1ae14361 #238 A=com.simple.myapplicaiton.task1 U=0 sz=1}
      Intent { flg=0x10000000 cmp=com.simple.myapplication/.B }
        Hist #0: ActivityRecord{e8fbd4d u0 com.simple.myapplication/.B t238}
          Intent { flg=0x10000000 cmp=com.simple.myapplication/.B }
          ProcessRecord{12776e86 300:com.simple.myapplication/u0a57}
    Task id #237
      TaskRecord{22b1347 #237 A=com.simple.myapplicaiton.task1 U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000
cmp=com.simple.myapplication/.A }
        Hist #0: ActivityRecord{31785bab u0 com.simple.myapplication/.A t237}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000
000 cmp=com.simple.myapplication/.A }
          ProcessRecord{12776e86 300:com.simple.myapplication/u0a57}

可以发现存在2个栈
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值