一、引言
很多朋友去面试的时候,可能都会被问到这样一个问题:
请给我详细描述一下Activity的生命周期,及其相关的启动模式。
生命周期我倒是知道一点,启动模式又是个什么玩意?如果你没有事先准备的话,可能会被问个措手不及。那么接下来,就让我带你深入的了解这个知识点。
(关于Activity的生命周期,在之前的文章中已经讲过了,感兴趣的小伙伴点击下面的链接,就可以查询到。)
《Android学习之浅谈Activity的生命周期》
二、四种启动方式
Activity中一共有四种启动模式,分别为:
- standard 标准启动模式
- singleTop
- singleTask
- singleInstance
它们主要是在AndroidMainifest文件中,通过给activity标签指定android:launchMode属性来设置。
在这里我们要了解一个概念,android是通过返回栈来管理活动的。而栈是一个后进先出的数据结构,所以每当我们创建一个新活动,它都会自动放在栈顶。当我们使用finish()销毁这个活动时,位于栈顶的活动就会出栈,前一个入栈的活动,就会重新出现在栈顶。我们的系统每次都会将栈顶的活动展现给用户。
了解了这些以后,我们来对这四种启动方式深入解析吧~
三、standard
standard是活动默认的启动方式。每当你创建一个新活动,它就会在返回栈中入栈,并处于栈顶的位置。而且它不会管你栈中是否已经存在这个实例,每次启动都会创建一个新的实例。
下面我们进行代码演示分析:
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.d(\"MainActivity\",this.toString());setContentView(R.layout.activity_main);findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {startActivity(new Intent(MainActivity.this,MainActivity.class));}});}}
在这里我们创建了一个按钮,用于在两个MainActivity之间的转跳。如果按照正常的来说,这个MainActivity已经被创建了,我们不管怎么转跳,都不会产生新的实例才对,但是事实并不是这样。我们查看下打印信息。
可以看到,我一共点击了两次按钮,它又重新创建了两个实例。这样你按返回键时,也需要点击三次才可以完全退出。
四、singleTop
了解了standard模式后,你可能会觉得不太合理对吧?为啥我已经存在了,还需要重新创建。但这是系统默认的启动方式,你也可以进行相关的修改。比如这种SingleTop模式。当你的返回栈栈顶已经是该活动,就可以直接进行调用,就不会重新创建新的实例
下面我们进行代码演示:
首先我们在AndroidMainifest文件中,修改其启动模式。
<activityandroid:name=\".MainActivity\"android:launchMode=\"singleTop\">
然后我们继续运行这个程序,会发现你不管点击多少次,都不会产生新的实例。因为这时候MainActivity已经处于栈顶了。
但是这种启动方式,还是会存在着一定的问题。我们首先创建一个点击事件,让MainActivity转跳到SecondActivity。
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.d(\"MainActivity\",this.toString());setContentView(R.layout.activity_main);findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {startActivity(new Intent(MainActivity.this,SecondActivity.class));}});}}
然后再在SecondActivity中,转跳回MainActivity
public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.d(\"SecondActivity\",this.toString());setContentView(R.layout.activity_second);findViewById(R.id.button_1).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {startActivity(new Intent(SecondActivity.this,MainActivity.class));}});}}
这时候查看打印信息:
这时候你会发现,它又重新创建了一个MainActivity,这是为什么呢?
其实很简单,因为刚开始MainActivity在栈顶,但当你转跳到另一个界面时,栈顶就会变成SecondActivity,所以这时候会重新创建一个MainActivity。
五、singTask
这个启动方式,就可以很好的解决之前出现的一切问题。因为当你使用这个启动方式,每一次都会在返回栈中检查是否存在该活动的实例,如果发现已存在,那么就会直接调用,并且将这个活动上的所有活动全部出栈。如果没有发现,那么就会创建一个新的实例。
下面进行代码演示:
首先我们在MainActivity中添加一个OnRestart方法:
@Overrideprotected void onRestart() {super.onRestart();Log.d(\"MainActivity\",\"OnRestart\");}
在SecondActivity中添加一个OnDestroy方法:
@Overrideprotected void onDestroy() {super.onDestroy();Log.d(\"SecondActivity\",\"OnDestroy\");}
执行后发现:
从这个打印信息我们可以得出,当刚开始启动时,MainActivity处于栈顶,转跳到SecondActivity以后,MainActivity就在底下了,这时候再返回MainActivity,就会将SecondActivity出栈,并重新调用MainActivity,也不要创建新的实例。按一次返回键就可以退出了。
六、SingInstance
这个启动方式就厉害了。它会给你这个活动创建一个新的返回栈,单独保存。这样有什么意义呢?这样可以实现其他程序和我们的程序,共享这个活动的实例。
下面进行代码演示:
首先我们将SecondActivity的启动方式改为singInstance
然后在MainActivity中添加一个打印信息:
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.d(\"MainActivity\",\"Task id is\" + getTaskId());setContentView(R.layout.activity_main);findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {startActivity(new Intent(MainActivity.this,SecondActivity.class));}});}
在SecondActivity中也添加一个打印信息:
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.d(\"SecondActivity\",\"Task id is\" + getTaskId());setContentView(R.layout.activity_second);
在ThirdActivity中也添加一个打印信息:
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.d(\"ThirdActivity\",\"Task id is\" + getTaskId());setContentView(R.layout.activity_third);
运行以后输出打印信息:
可以看出MainActivity和ThirdActivity在一个栈中,SecondActivity在另一个栈中。
但是当我们按下返回键以后,会发现直接从ThirdActivity直接返回到MainActivity,然后再按一下返回,又会返回到SecondActivity,最后按一下back才能退出。为什么会出现这种情况呢?其实很简单,因为MainActivity和ThirdActivity处于一个栈中,当ThirdActivity出栈后,MainActivity就会出现在栈顶。等MainActivity出栈后,这个栈就空了,所以调用另一个栈。也就是SecondActivity所在的栈。最后按一下返回,所以的栈都空了,所以退出程序。
七、小结
Activity的四种启动方式就先讲到这里吧。我觉得整个文章还是比较好理解的,而且所有的步骤都是有代码演示,也比较的清晰。最后希望这篇文章能够帮助到大家,一起共同进步呀!