启动模式的作用
在日常开发中,当默认情况下我们多次启动同一个Activity的时候,系统会创建多个实例并把它们一一放入任务栈,当我们每单击back键,就会栈顶移除一个Activity,直到栈空为止,当栈中没有任何Activity时,系统就会回收这个任务栈。为了优化多次启动同一个Activity而创建多个实例带来的内存消耗问题,Android提供了四种启动模式来修改默认行为。
目前四种启动模式分别是:standard、singleTop、singleTask、singleInstance;
为了方便分析了log日志打印,定义了一个基类:
/**
* author:hzw on 2017/12/20
* desc: 方便于打印的基类
*/
public class BaseActivity extends AppCompatActivity{
public static final String TAG = "BaseActivity";
private String getClassName(){
return getClass().getSimpleName()+"--";
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getSupportActionBar()!=null){
getSupportActionBar().setTitle(getClassName());
}
Log.d(TAG, getClassName()+"onCreate(): taskId"+getTaskId());
dumpTaskAffinity();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.i(TAG,getClassName()+"onNewIntent: taskId"+getTaskId());
dumpTaskAffinity();
}
protected void dumpTaskAffinity(){
try {
ActivityInfo info = this.getPackageManager()
.getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
Log.i(TAG, getClassName()+"taskAffinity:"+info.taskAffinity);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
}
standard 默认模式
standard是标准模式,也是系统的默认模式。在不指定启动模式(LaunchMode)的情况下,系统会默认使用该启动模式,该模式的特点就是,每次启动一个Activity都会重新创建一个新的实例,不管这个Activity的实例是否已经存在。被创建的Activity的实例都会与正常典型的Activity生命周期一样的,比如onCreate、onStart、onResume方法都会被调用。这就是典型的多实例实现,一个任务栈中可以有多个实例,在这种模式下,谁启动了这个Activity,那么这个Activity就会在启动的那个Activity所在的栈中。
配置方式:
<activity android:name=".StandardActivity" android:launchMode="standard"/>
对于standard模式可以不用launchMode声明,系统默认情况下已经是standard了
测试案例
在NextActivity中启动一个StandardActivity,同时也在StandardActivity中再次启动一个StandardActivity
NextActivity :
public class NextActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next);
findViewById(R.id.bt_standard).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//标准模式 standard;
Intent intent = new Intent(NextActivity.this, StandardActivity.class);
startActivity(intent);
}
});
}
}
StandardActivity :
public class StandardActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_standard);
findViewById(R.id.bt_standard).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//再次连续启动
Intent intent = new Intent(StandardActivity.this, StandardActivity.class);
startActivity(intent);
}
});
}
}
在进入了StandardActivity后,再次连续启动StandardActivity,然后按back键依次退出。
Log日志输出:
03-26 15:09:27.367 3628-3628/com.hzw.tapp D/BaseActivity: NextActivity--onCreate() taskId:7
03-26 15:09:27.367 3628-3628/com.hzw.tapp I/BaseActivity: NextActivity--taskAffinity:com.hzw.tapp
03-26 15:09:27.377 3628-3628/com.hzw.tapp I/BaseActivity: NextActivity--onStart()
03-26 15:09:27.377 3628-3628/com.hzw.tapp I/BaseActivity: NextActivity--onResume()
03-26 15:09:37.067 3628-3628/com.hzw.tapp I/BaseActivity: NextActivity--onPause()
03-26 15:09:37.077 3628-3628/com.hzw.tapp D/BaseActivity: StandardActivity--onCreate() taskId:7
03-26 15:09:37.077 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--taskAffinity:com.hzw.tapp
03-26 15:09:37.077 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onStart()
03-26 15:09:37.077 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onResume()
03-26 15:09:37.447 3628-3628/com.hzw.tapp I/BaseActivity: NextActivity--onStop()
03-26 15:09:44.487 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onPause()
03-26 15:09:44.497 3628-3628/com.hzw.tapp D/BaseActivity: StandardActivity--onCreate() taskId:7
03-26 15:09:44.497 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--taskAffinity:com.hzw.tapp
03-26 15:09:44.497 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onStart()
03-26 15:09:44.497 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onResume()
03-26 15:09:44.877 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onStop()
03-26 15:37:57.387 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onPause()
03-26 15:37:57.397 3628-3628/com.hzw.tapp D/BaseActivity: StandardActivity--onCreate() taskId:7
03-26 15:37:57.397 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--taskAffinity:com.hzw.tapp
03-26 15:37:57.397 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onStart()
03-26 15:37:57.397 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onResume()
03-26 15:37:57.797 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onStop()
从日志可以看出,启动了一次NextActivity和三次StandardActivity,而每次启动的StandardActivity的taskId都是与NextActivity的taskId一样的,由此可以证明谁启动了这个Activity,那么这个Activity就会在启动的那个Activity所在的栈中,同是每次启动StandardActivity,都会调用onCreate、onStart、onResume方法,证明了每次启动一个Activity都会创建一个新Activity实例。
singleTop 栈顶复用模式
在这个模式下,如果新Activity已经存在于任务栈栈顶,那么Activity不会被重新创建,同时它会调用onNewIntent方法,可以通过此方法可以取出所携带的信息,是不是调用onCreate、onStart方法;如果新Activity实例已存在但不在栈顶(或者新Activity在栈中不存在实例),那会新Activity依然重新创建一个实例。
配置方式
<activity android:name=".SingleTopActivity" android:launchMode="singleTop"/>
或者:
Intent intent = new Intent(NextActivity.this, SingleTopActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
测试案例
SingleTopActivity:
public class SingleTopActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_top);
String singleTop = getIntent().getStringExtra("singleTop");
Log.i(TAG,singleTop+"");
findViewById(R.id.bt_test_single_top).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//位于栈顶的情况
Intent intent=new Intent(SingleTopActivity.this,SingleTopActivity.class);
intent.putExtra("singleTop","singleTop");
startActivity(intent);
}
});
findViewById(R.id.bt_not_top).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//不在栈顶的情况
startActivity(new Intent(SingleTopActivity.this,OtherTopActivity.class));
}
});
}
}
OtherTopActivity :
public class OtherTopActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other_top);
findViewById(R.id.bt_single_top).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(OtherTopActivity.this,SingleTopActivity.class));
}
});
}
}
第一种情况:新Activity位于栈顶
从日志上可见,当新Activity已经在栈顶时,再次启动,并不会调用新Activity的onCreate、onStart方法,可见此Activity并没有重新创建,只是调用了onNewIntent方法获取需要的信息,再去执行onResume方法得到焦点显示到前台。
第二种情况:新Activity已经存在于栈中,但不在栈顶
从日志可见,当新Activity已经存在于栈中,但不在栈顶,此时新Activity会重新创建一个实例,会调用典型的生命周期onCreate、onStart、onResume.
第三情况:就是当栈内不存在新Activity实例,此时同Standard模式一样的。
singleTask-栈内复用模式
singfleTask是一种单实例模式,就是只要栈中存在该Activity实例,那么多次启动该Activity都不会创建新实例,和singleTop一样,系统会回调其onNewIntent方法。同时singleTask启动模式与TaskAffinity属性有直接的关系。
TaskAffinity称为任务相关性,这个参数标识一个Activity所需要的任务栈名字,默认情况下,所以Activity所需的任务栈名字为应用的包名,当然,也可以为每个Activity都单独指定TaskAffinity属性,这个属性必须不能和包名相同,否则就相当于没有指定。
接下分析下TaskAffinity与singleTask启动模式的相关性
第一种情况:当ActivityA与ActivityB的TaskAffinity相同时
先在AndroidMainfest文件中为Activity指定相同的TaskAffinity属性值,都为应用包名。
<activity android:name=".NextActivity"
android:taskAffinity="com.hzw.tapp"/>
<activity
android:name=".SingleTaskActivity"
android:launchMode="singleTask"
android:taskAffinity="com.hzw.tapp"/>
<activity android:name=".OtherTaskActivity"/>
从日志上可见,使用singleTask启动模式,当任务栈中存在Activity实例时,此时再次启动该Activity并不会重新创建新实例,而是复用之前该Activity的实例,并调用onNewIntent方法获取相关信息,同时也会把该Activity之上所有的activity实例从任务栈中移除销毁,使该Activity保持在栈顶中;当任务栈中不存在该Activity实例,此时会创建一个Activity实例放入该任务栈中。
第二种情况:当ActivityA与ActivityB的TaskAffinity属性值不同时
<activity android:name=".NextActivity"
android:taskAffinity="com.hzw.tapp"/>
<activity
android:name=".SingleTaskActivity"
android:launchMode="singleTask"
android:taskAffinity="com.hzw.tapp.task"/>
<activity android:name=".OtherTaskActivity"/>
NextActivity启动SingleTaskActivity,TaskAffinity属性值不同时,系统会先创建一个所需的任务栈(com.hzw.tapp.task),然后再创建SingleTaskActivity的实例并将其放入任务栈(com.hzw.tapp.task)中,这点是与情况一的不同之处。
singleInstance 单实例模式
singleTask模式其实就是singleTask的加强版,它除了具有singleTask模式所有特性外,还加强一点就是在此模式下的Activity只能单独在一个任务栈中。
<activity
android:name=".SingleInstanceActivity"
android:launchMode="singleInstance"/>
从日志可见,当NextActivity启动SingleInstanceActivity时,两者的taskId是不一样的,新建了一个任务栈,同时在SingleInstanceActivity中再次启动一个SingleInstanceActivity,此时可以看出,是不会重新创建一个任务栈和Activity实例,都是复用之前的,Activity会调用onNewIntent方法,这和singleTask模式是一样的。