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。
附上测试代码:
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()方法。
附上测试代码:
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()函数。
附上测试代码:
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只能单独的位于一个任务栈中
附上测试代码:
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个栈