1.为什么要使用启动模式?
在我们的Android开发之中,当我们多次启动同一个Activity的时候,系统汇创将多个重复的实例,将他们放到任务栈之中。当我们点击返回键的时候,这些Activity实例又将从任务栈中一一移除,遵循栈“后进先出”的原则。
2.启动模式的分类
1.默认模式 Standard
说明: Android创建Activity时的默认模式,假设没有为Activity设置启动模式的话,默觉得标准模式。每次启动一个Activity都会又一次创建一个新的实例入栈,无论这个实例是否存在。
生命周期:如上所看到的,每次被创建的实例Activity 的生命周期符合典型情况,它的onCreate、onStart、onResume都会被调用。
-
在Manifest中配置:对于标准模式,android:launchMode=”standard”可以不写,因为默认就是standard模式。
-
启动Activity的时候。在Intent中指定启动模式去创建Activity
通过Intent的addFlags方法去动态的指定一个启动模式。
Intent intent = new Intent();
intent.setClass(context, MainActivity.class);
context.startActivity(intent);
这时我们不需要去设置启动Flags,默认就是standard启动
2.SingleTop 栈顶复用模式
说明:分两种处理情况:须要创建的Activity已经处于栈顶时,此时会直接复用栈顶的Activity。不会再创建新的Activity;若须要创建的Activity不处于栈顶,此时会又一次创建一个新的Activity入栈,同Standard模式一样。
生命周期:若情况一中栈顶的Activity被直接复用时,它的onCreate、onStart不会被系统调用,由于它并没有发生改变。可是一个新的方法 onNewIntent会被回调(Activity被正常创建时不会回调此方法)。
-
在 Manifest.xml中指定Activity启动模式
-
启动Activity时。在Intent中指定启动模式去创建Activity
Intent intent = new Intent();
intent.setClass(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
这里的FLAG_ACTIVITY_SINGLE_TOP就是我们设置的标记位,作用就是为Activity指定“singleTop”启动模式
3.栈内复用模式
说明:若须要创建的Activity已经处于栈中时,此时不会创建新的Activity,而是将存在栈中的Activity上面的其他Activity所有销毁,使它成为栈顶。
生命周期:同SingleTop 模式中的情况一同样。仅仅会又一次回调Activity中的 onNewIntent方法
-
在Manifest中配置:
-
启动Activity时。在Intent中指定启动模式去创建Activity
Intent intent = new Intent();
intent.setClass(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
这里的FLAG_ACTIVITY_NEW_TASK就是我们设置的标记位,作用就是将Activity的启动模式设置为singleTask
4.SingleInstance:单例模式的实现
-
在Manifest中配置:
这里的SingleInstance才是四种启动模式中的重点,它具备所有的SingleTask的特点,就是一种加强的singleTask。但是和别的四种启动模式不同的是:这种启动模式会单独的创建一个任务栈,上面的三种启动模式都是存在于同一个任务栈之中,而这种的模式存在于另一个任务栈之中。这样的存在模式使用的时候可能存在这一些问题,下面我们在进行分析。
我们定义了ActivityA和ActivitySecond两个界面
当我们启动ActivityA后:
点击按钮进入ActivitySecond
当我们退出去之后暂时退出去后,重新进入后返回的结果:
这里的原因是:当我们重新进入的时候,我们会重新的在主任务栈进行查找,若没有就会进行创建,但是我们的SecondActivity在另外的一个任务栈之中,这样当我们使用了home键暂时的退出程序后再进入,此时会调用主任务栈中栈顶Activity的onRestart,不会调
用SecondActivity的onRestart。
想着查询一些资料找到解决的办法,但是后来发现其实这个问题根本不需要解决。
因为我们此时根本不需要将我们的launchMode设置为singleInstance,这样的启动模式只会运用在一些特定的需要独立栈操作的应用上面。比如说:呼叫来电界面。当我们正在A应用中看视频的时候,接收到来电,点击进入到来电详情界面,当我们点击返回之后就回到A视频的界面,这样就不会干扰到用户之前的操作。
这个时候我们只会产生一个单独运行的Activity的界面,这个Activiyt会具有全局唯一性,整个系统之中只会存在一个这样的实例;
其实上面的呼叫来电的界面和我们的ActivitySecond界面大同小异,我们的ActivityA就相当于上面的应用A,只不过,当我们退出通话界面的时候,系统会挂起通话界面也就是实现onPause,但是此时通话任务任然的进行,通话界面之中虽然可以可以控制通话的结束,但是两者的生命周期却是没有进行绑定。当我们的通话任务结束的时候才能够对通话界面进行销毁。
这样的功能都是可以在我们的ActivitySecond界面的基础之上进行实现。
3.复用Activity时的生命周期回调
由于当一个Activity设置了SingleTop或者SingleTask模式后,跳转此Activity出现复用原有Activity的情况时,此Activity的onCreate方法将不会再次运行。onCreate方法仅仅会在第一次创建Activity时被运行。
而一般onCreate方法中会进行该页面的数据初始化、UI初始化,假设页面的展示数据无关页面跳转传递的參数,则不必操心此问题,若页面展示的数据就是通过getInten() 方法来获取,那么问题就会出现:getInten()获取的一直都是老数据,根本无法接收跳转时传送的新数据!
public class CourseDetailActivity extends BaseActivity{
......
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_course_detail_layout);
initData();
initView();
}
//初始化数据
private void initData() {
Intent intent = getIntent();
mCourseID = intent.getStringExtra(COURSE_ID);
}
//初始化UI
private void initView() {
......
}
......
}
以上代码中的CourseDetailActivity在配置文件里设置了启动模式是SingleTop模式,依据上面启动模式的介绍可得知,当CourseDetailActivity处于栈顶时。再次跳转页面到CourseDetailActivity时会直接复用原有的Activity,并且此页面须要展示的数据是从getIntent()方法得来,可是initData()方法不会再次被调用,此时页面就无法显示新的数据。
当然这样的情况系统早就为我们想过了,这时我们须要另外一个回调 onNewIntent(Intent intent)方法。当我们复用Activity的时候就会调用此方法,不复用就不会调用。此方法会传入最新的intent,这样我们就能够解决上述问题。这里建议的方法是又一次去setIntent。然后又一次去初始化数据和UI。代码例如以下所看到的:
/*
* 复用Activity时的生命周期回调
*/
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
initData();
initView();
}
那么onNewIntent都会在什么情况下调用呢?
前提:ActivityA已经启动过,处于当前应用的Activity堆栈中;
当ActivityA的LaunchMode为SingleTop时,如果ActivityA在栈顶,且现在要再启动ActivityA,这时会调用onNewIntent()方法
当ActivityA的LaunchMode为SingleInstance,SingleTask时,如果已经ActivityA已经在堆栈中,那么此时会调用onNewIntent()方法