Android--探讨Activity的生命周期

文章首发在个人公众号:追风栈Binary。希望共同交流和相互探讨。

当我们在评价一个App的时候,经常会从流畅度、稳定性以及人性化这些角度去多维度的比较。一些操作流畅、页面精美的App即使没有什么大的实用意义,但我们都会选择多看几眼,相反的是,如果一个App启动慢,页面滑动卡顿,经常需要重新加载页面信息,那么毫无疑问,卸载是对它最后的仁慈。Android开发是通过Activity(活动)来完成与用户的交互,除了Activity的页面内容要丰富以外,也需要关注一个Activity是如何启动的,它的生命历程到底是怎么样的,我们才可以更好的优化应用程序。

什么是Activity?

简单的说,Activity就是应用程序的一个个页面,例如下面的两个应用程序的页面,制作的非常精美。

Activity是Android应用程序重要的组成部分,它直接面向用户,接受用户的输入,并按照用户的意图来响应相应的操作。也正是因为它与用户直接交互,也就注定了Activity在应用程序中的重要性,就拿主页面来讲,如果连打开程序的主页面进行操作都会觉得卡顿不适的话,那用户很大可能就因此失去了了解这款App的兴趣,他可能就会选择不再打开或者直接卸载。所有的App都强调用户体验第一,就是这个道理。

如何形象的理解应用程序中的Activity

使用任何App的时候,我们可以感受得到页面仿佛是可以堆叠的,例如在主页面点击了一个登录按钮后就会跳转至登录详情页,登陆成功后就又会返回到我们的主页面。那么显示登录页面的时候,主页面去哪里了?为什么后面它又会原封不动的回来?

实际情况与我们对于这种切换的认知是一致的,Activity可以堆叠,我们切换页面,使得不同的页面显示在当前的屏幕中,而之前的页面被系统管理了起来。以箱子和同等大小的木板来做类比,过程如下:

  • 箱子是一个管理Activity的机制,木板就是一个个的Activity

  • 我们永远只能看到箱子最上面的那块木板,意味着我们只能看到显示在屏幕当前的Activity

  • 我们点击进入新的页面,就好比往箱子里添加了一块新的木板,此时新木板处于最顶端,也正是我们看到的页面

  • 当我们返回上一个页面时,就好比把最上面的木板从箱子里抽取出来,我们回到了原来的界面

  • 当程序退出时,相当于木板都被抽取出来,箱子此时是空的。

Android使用Task来管理活动,一个Task就是一组Activity的集合,而上面的箱子,在Android中被称为返回栈,栈的特性就是和箱子一样,先进来的反而后出去。这也和我们使用App的感受一致,如果从主页面点开另一个页面,然后从另一个页面点开再另一个页面...,到后面要返回到主页面时,就不得不一直按返回键,直到最后达到主页面。其实这些操作,就是Activity不断入栈和出栈的过程。

Activity生命周期中有哪些方法?

在新建一个Android Studio工程的时候,选择Empty Activity后,会自动的创建一个MainActivity,并且会自动的在AndroidManifest文件中声明该Activity为启动页面:


 
 
 
 

也就是说,点击应用图标后,首先映入眼帘的就是这个界面(当然这个指的是主页面,而并不是指启动页面)。可以指定任何程序中的Activity作为程序的主页面,但是需要在AndroidManifest文件中进行的相关配置。

Android对Activity生命周期定义了七种方法,分别如下:

  • onCreate():指的是Android系统初次创建这个Activity时调用的方法,这是一个必须实现的方法,我们需要在里面设置setContentView()方法,并且还要进行一系列控件的绑定,onCreate()接收一个savedInstanceState的参数,这个参数的意思是保存Activity先前状态的信息,但是如果是第一次创建,那么saveInstanceState中就没有任何的信息。

  • onStart():指的是系统将这个Activity变为用户可见,这个方法执行的十分快速,紧接着就是onResume()

  • onResume(): 指的是Activity准备好与用户进行交互了,此时它处于返回栈的栈顶,是用户直接接触的对象

  • onPause(): 指的是当Activity不再是处于栈顶,但它可能还是会对用户可见的时候,一般指的是当前页面突然弹出一个对话框,此时Activity就是处于onPause()状态

  • onStop(): 指的是当Activity完全不可见的时候,例如主页面跳转到登录页面,那么此时主页面就是处于onStop状态

  • onDestroy(): 指的是Activity将要被销毁了,例如在主页面按返回键回到桌面时,会调用此方法

  • onRestart(): 当ActivityonStop()状态到onStart()状态下切换时调用,例如从登录页面返回到主页面

本来打算自己画一个流程图,但是Android指南上的流程图太经典了,绘制的很详细,所以直接把那幅图搬到这里来。


还可以看出,除了onRestart(),其余的六种方法都是配对出现的,onCreate()对应onDestroy()onStart()对应onStop()onResume()对应onPause()

Activity的生命周期示例

文章的重点是讨论Activity的生命周期,也就是要探讨程序启动、页面跳转、弹出对话框、程序退出等场景时Activity的行为,具体分析如下两个方面

  • Activity在这些场景下,它做了哪些事情

  • Activity在这些场景下,它分别处于什么状态

为了更直观的展示,建立了一个ActivityLifeCycleDemo的示例,很多时候Android Studio默认生成了必须重写的onCreate()方法,而其他方法则默认继承父类方法,导致我们无法查看生命周期状态,这个例子重写了继承的方法,加入了Log以便打印信息

跳转逻辑:MainActivity(启动主页面)、点击"跳转至正常的Activity"跳转到"这是正常的Activity"、点击"跳转至对话框Activity"跳转到"这是对话框的Activity"


// MainActivity代码,重写了继承父类的一些方法
@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 Log.d(TAG, "1: 我在onCreate()方法");
 setContentView(R.layout.activity_main);
 initView();
}
​
private void initView(){
 Button turnToNormal = findViewById(R.id.start_normal);
 Button turnToDialog = findViewById(R.id.start_dialog);
​
 turnToNormal.setOnClickListener(this);
 turnToDialog.setOnClickListener(this);
}
​
@Override
public void onClick(View view) {
 switch (view.getId()){
 case R.id.start_normal:
 Intent normalIntent = new Intent(this, NormalActivity.class);
 startActivity(normalIntent);
 break;
 case R.id.start_dialog:
 Intent dialogIntent = new Intent(this, DialogActivity.class);
 startActivity(dialogIntent);
 break;
 default:
 break;
 }
}
​
@Override
protected void onStart() {
 super.onStart();
 Log.d(TAG, "2: 我在onStart()方法");
}
​
@Override
protected void onResume() {
 super.onResume();
 Log.d(TAG, "3: 我在onResume()方法");
}
​
@Override
protected void onPause() {
 super.onPause();
 Log.d(TAG, "4: 我在onPause()方法");
}
​
@Override
protected void onStop() {
 super.onStop();
 Log.d(TAG, "5: 我在onStop()方法");
}
​
@Override
protected void onDestroy() {
 super.onDestroy();
 Log.d(TAG, "6: 我在onDestroy()方法");
}
​
@Override
protected void onRestart() {
 super.onRestart();
 Log.d(TAG, "7: 我在onRestart()方法");
}

1.当点开程序图标,MainActivity中发生了什么?

点击程序图标,进入MainActivity,显示主页面。由于打印了Log日志,所以可以使用Logcat查看这些输出信息。

可以看到Logcat打印出了三条信息,并且调用方法的顺序依次是onCreate()onStart()onResume()。这说明当系统第一次启动该应用的时候,会通过onCreate方法来创建一个MainActivity的实例,完成控件和事件的绑定,例如上面程序中的findViewById()onClick()这些方法。并随后调用onStart()onResume()的方法,这些方法的执行很快,从时间上看,两个方法几近是同一时刻调用的。完成这三个方法后,主页面显示在用户面前,并一直处于onResume状态。

2.从MainActivity切换到正常的Activity,会发生什么?

点击主页面的跳转至正常的Activity按钮,程序会跳转到另外一个界面上:

查看Logcat的输出信息

可以看出,从MainActivity跳转至另外一个Activity时,MainActivity会依次调用onPause()onStop()的方法,正如指南中所说,当Activity完全不可见时,调用onStop()的方法,这一点在示例中得到了验证。现在MainActivity不再处于栈顶,处于栈顶的是这个正常的Activity

3.从正常的Activity返回到主页面会调用什么?

现在我们要返回到MainActivity,通过按返回键就可以实现:

查看Logcat的输出信息

注意,从完全不可见恢复到完全可见的状态,是通过调用onRestart()方法来实现的,然后再依次调用onStart()onResume()方法,重新获得焦点,现在MainActivity又回到了栈顶了。

4.从MainActivity到对话框Activity,又会发生什么?

我们现在从MainActivity出发,点击跳转至对话框Activity按钮,跳至对话框页面。但要注意,对话框是一种局部覆盖MainActivity的页面,它不会让MainActivity完全消失。

查看Logcat,看看这个过程与上一个过程到底有何不同。

这个调用过程并不像是上面过程一样,这里的MainActivity只调用了onPause()方法,而没有继续调用onStop()方法,这说明MainActivity并没有完全消失,从直观的角度来看,我们仍然可以看得到对话框下的MainActivity,只不过是被对话框页面蒙上了一层灰色。

5.从对话框页面返回MainActivity,会发生什么?

现在从对话框页面点击返回键回到主页面

查看Logcat的输出信息

从对话框跳回至MainActivityMainActivity直接调用了onResume()方法,这一步也没有调用onRestart()方法。

6.在MainActivity上按返回键退出,会发生什么?

测试在主页面上直接按返回键,返回到手机桌面上,这一步过程中MainActivity会调用哪些方法。依旧查看Logcat,查看输出信息:

退出应用时,程序相当于被关闭了。MainActivity依次调用onPause()onStop()之后,会调用onDestroy()方法来销毁自身。那如果不是按返回键,而是按Home键回到桌面上,那会有区别吗?

7. 在MainActivity上按HOME键回到桌面,会发生什么?

MainActivity上直接按Home键,也同样会回到桌面上,那么此时MainActivity会把自身销毁掉吗?查看Logcat的输出结果,就会知道答案。

Logcat的输出结果表明,点按Home键回到桌面上时,MainActivity并不会调用onDestroy()的方法,反而是和MainActivity被另一个页面覆盖的结果相同。但是这种方式回到桌面,那么程序很有可能会被后台管理程序回收,这就是为什么有时我们打开微信后又回到桌面上,过一段时间打开微信需要重新进入的原因。

至此,Activity生命周期的讨论就可以先告一段落了。

如何快速的记住这些方法?

都说把它们全部理解了,就顺便记下来了。但我觉得,可能先记下来,再后面遇到了慢慢理解也不迟。七个方法按一个Activity创建到销毁的顺序来,会好记很多。

我个人喜欢用通俗的方式来记忆,比如说这七个方法,除去特殊的onStart()外,按照每个方法的大写字母来顺序排列,那就是C-S-R-P-S-D,其中C-S就记忆成反恐精英R-P记忆成人品S-D记忆成SD卡,最后只需要单独记忆一个onStart()就可以了。

你可能感兴趣的:(Android--探讨Activity的生命周期)