Activity及生命周期
前言
Activity是Android组件中最基本也是最为常见用的四大组件之一,而 Activity 的启动和组合方式则是该平台应用模型的基本组成部分,而 Android 系统与此不同,它会调用与其生命周期特定阶段相对应的特定回调方法来启动 Activity 实例中的代码。
提示:以下是本篇文章正文内容,供参考
一、Activity与用户交互
几乎所有activity都与用户交互,因此Activity类负责为您创建一个窗口,您可以在其中放置UI setContentView(View),activity通常以全屏窗口的形式呈现给用户,但它也可以以其他方式使用:
- 浮动窗口(通过R.attr.windowIsFloating设置了主题 的窗口),多窗口模式或嵌入到其他窗口。
- 几乎所有Activity的子类都会实现两种方法:
onCreate(Bundle)是您初始化Activity,最重要的是,这里通常会调用setContentView(int) 一个布局资源来定义您的UI,并使用findViewById(int) 该资源来检索您需交互的UI中的小部件。
onPause()是您与用户之间暂停与活动进行主动交互的地方,用户此时所做的任何更改都应提交(通常用于 ContentProvider保存数据),在这种状态下,activity仍在屏幕上是可见性;- 要与Activity配合使用Context.startActivity(),所有activity类必须在AndroidManifest.xml 声明<activity标签。
二、Activity周期与概念
1. 理解Activity生命周期
- 当用户浏览、退出和返回应用时,应用中的 Activity 会在其生命周期的不同状态直间进行转换,Activity 类会提供许多回调,这些回调会让 Activity 知晓某个状态已经更改:系统正在创建、停止或恢复某个 Activity,或者正在销毁该 Activity 所在的进程。
- 在合适的时间执行正确的作业,并妥善处理转换,这将提升应用的稳健性和性能。例如,良好的生命周期回调实现有助于确保您的应用避免:
a.当用户在使用应用时接听来电,或切换至另一应用时崩溃。
b.当用户未积极使用它时,消耗宝贵的系统资源。
c.当用户离开应用并在稍后返回时,丢失用户的进度。
d.当屏幕在横向和纵向之间旋转时,崩溃或丢失用户的进度。
2. 生命周期概念
为了在 Activity 生命周期的各个阶段之间转换,Activity 提供了六个核心回调:onCreate()、onStart()、onResume()、onPause()、onStop() 和 onDestroy()。当 Activity 进入新状态时,系统会调用每个回调,当用户开始离开Activity时,系统会调用方法来销毁该Activity。
- 在某些情况下,此销毁只是部分销毁,Activity 有时候仍然驻留在内存中(例如当用户切换至另一应用时),并且仍然可以返回前台,如果用户返回该Activity,则Activity会从用户离开时的位置继续运行,少数应用例外,在后台运行时会受到限制,无法启动 Activity。
- 系统终止给定进程及其中 Activity 的可能性取决于当时 Activity 的状态。
在开发过程中,可能不需要实现所有生命周期方法。但是,请务必了解每个方法,并实现能够确保应用按用户期望的方式运行的方法,这些是非常重要
三、Activity生命周期
1. Activity四个状态
上图显示了activity活动的重要状态路径,正方形表示当Activity在活动状态之间移动时可以实现以执行操作的回调方法,彩色椭圆形是activity可以进入的主要状态,下面我们来了解各个生命周期之前,我们得先知道它的状态,那么它有几个状态呢?
a.如果Activity位于屏幕的前端(最顶层堆栈的最高位置),则该activity处于activity状态或正在运行。这通常是用户当前正在与之交互的activity。
b.如果某项activity失去了焦点,但仍呈现给用户,则它是可见的。如果一个新的非全尺寸或透明activity集中在您的activity顶部,另一个activity在多窗口模式下处于较高位置,或者该activity本身在当前窗口模式下无法聚焦,则是可能的。这样的activity是完全活着的(它维护所有状态和成员信息,并保持附加到窗口管理器中)。
c.如果一个activity完全被另一个activity遮盖,则将其停止或隐藏。它仍然保留所有状态和成员信息,但是,它对用户不再可见,因此它的窗口是隐藏的,当其他地方需要内存时,它会被系统杀死。
d.系统可以通过要求完成activity或简单地终止其进程以使其破坏而从内存中删除该activity。当再次将其显示给用户时,必须完全重新启动它并将其还原到以前的状态。
2. Activity 生命周期onCreate()
- onCreate():必须实现这个方法,当系统第一次创建这个activity,当activity被创建的时候,会执行基础的启动逻辑,这些逻辑代码只会发生一次在整个activity生命周期中。
例如:实现绑定list数据,用viewModel把activity关联起来,实例化一些类变量。这个方法接受一个形参,savedInstanceState,这是一个Bundle对象,包含activity之前的状态。如果activity在此之前不存在,这个Bundle是空的。- 下述code 展示 Activity 的基本设置,例如:声明界面(在 XML 布局文件中定义)、定义成员变量,以及配置某些界面,系统通过将文件的资源 ID R.layout.activity_test_main 传递给 setContentView() 来指定 XML 布局文件。
public class TestActivity extends Activity {
private static final String GAME_STATE_KEY = "key_1";
private String gameState;
private TextView textView;
private String TEXT_VIEW_KEY = "key_2";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
android.util.Log.d("TestActivity", "onCreate savedInstanceState:" + savedInstanceState);
//检查是否正在重新创建一个以前销毁的实例
if (savedInstanceState != null) {
gameState = savedInstanceState.getString(GAME_STATE_KEY);
}
setContentView(R.layout.activity_test_main);
textView = (TextView) findViewById(R.id.text_view);
textView.setText("TestActivity");
}
@Override
protected void onResume() {
super.onResume();
android.util.Log.d("TestActivity", "onResume");
}
@Override
protected void onRestart() {
super.onRestart();
android.util.Log.d("TestActivity", "onRestart");
}
@Override
protected void onStart() {
super.onStart();
android.util.Log.d("TestActivity", "onStart");
}
@Override
protected void onPause() {
super.onPause();
android.util.Log.d("TestActivity", "onPause");
}
@Override
protected void onStop() {
super.onStop();
android.util.Log.d("TestActivity", "onStop:");
}
@Override
protected void onDestroy() {
super.onDestroy();
android.util.Log.d("TestActivity", "onStop:");
}
//当前存在以前使用onSaveInstanceState()已保存实例时,才调用此回调。
//在onCreate()中还原了一些状态,而在这里我们可以选择还原其他状态,可能在onStart()完成后才可用。
//saveInstanceState捆绑包与onCreate()中使用的捆绑包相同。
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
//总是调用,以便它可以恢复视图层次超级
super.onRestoreInstanceState(savedInstanceState);
//从已保存的实例中恢复状态成员
String key_2 = savedInstanceState.getString(TEXT_VIEW_KEY);
android.util.Log.d("TestActivity", "onRestoreInstanceState key_2:" + key_2);
textView.setText(key_2);
}
//当Activity可能被临时破坏时调用,在此处保存实例状态,比如横屏切换;
@Override
protected void onSaveInstanceState(Bundle outState) {
android.util.Log.d("TestActivity", "onSaveInstanceState");
//保存用户自定义的状态
outState.putString(GAME_STATE_KEY, gameState);
outState.putString(TEXT_VIEW_KEY, textView.getText().toString());
//调用父类交给系统处理,这样系统能保存视图层次结构状态
super.onSaveInstanceState(outState);
}
}
activity_test_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="button_1"
/>
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/autofill"/>
</LinearLayout>
AndroidManifest.xlm
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.all.test.application">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".TestActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
3. onSaveInstanceState()和onRestoreInstanceState()使用
- 看到上面面code后,这里是为了让Activity添加额外的数据到已保存的实例状态,Activity生命周期中还有一个额外的回调方法,这些回调方法在前面的课程中没有显示。该方法是onSaveInstanceState(),系统在用户离开Activity时调用它。当系统调用此方法时,它将传递Bundle将在您的Activity意外销毁的事件中保存的对象,以便您可以向其中添加其他信息。如果系统在被销毁之后必须重新创建Activity实例,它会将相同的Bundle对象传递给您的Activity的onRestoreInstanceState()方法以及您的onCreate() 方法。
- 如上图所示:
当系统开始停止您的Activity时,它会调用onSaveInstanceState() (1),以便您可以指定要保存的其他状态数据,以防Activity必须重新创建实例。如果Activity被破坏并且必须重新创建相同的实例,则系统将 (2) 中定义的状态数据传递给onCreate()方法 (2) 和onRestoreInstanceState()方法 (3)。
- 这里需注意两点:
a.如果是用户自动按下返回键,或程序调用finish()退出程序,是不会触发onSaveInstanceState()和onRestoreInstanceState()的。
b.每次用户旋转屏幕时,您的Activity将被破坏并重新创建。当屏幕改变方向时,系统会破坏并重新创建前台Activity,因为屏幕配置已更改,您的Activity可能需要加载替代资源(例如布局)。即会执行onSaveInstanceState()和onRestoreInstanceState()的。
onCreate()可以选择执行onRestoreInstanceState(),而不是在系统调用onStart()方法之后恢复状态。系统onRestoreInstanceState()只有在存在保存状态的情况下才会恢复,因此不需要检查是否Bundle为空。
有兴趣的同学可以参考上面code自己横竖屏演示一下。
4. Activity 生命周期onStart()和onRestart()
- onStart 当activity进入开始状态时,系统调用这个回调方法,这个方法将会让activity变得用户可见,app会准备进入前端和变得可交互,例如,这个方法初始化维护UI的代码,这个状态会完成的十分快,不会保留太长时间,系统将调用 onResume()方法。
- onRestart 只有在点击home键,当前activity处于onStop状态时,重新进入Activity,则会执行onRestart,这里需注意的是,如果当前activity被销毁,则不会再执行onRestart,重新启动activity则直接走onCreate -> onStart->onResume。
5. Activity 生命周期onResume()
- 当Activity 进入 Resume 状态时,系统调用 onResume() 方法,这时 是应用与用户互动的状态,这种状态"应用"会一直保持着,直到某些事件发生,让焦点远离此“应用”,比如:来电、用户导航到另一个 Activity,或设备屏幕关闭等。
- 当 Activity 进入Resume状态时,与 Activity 生命周期相关联的所有生命周期的”感知型组件”都将收到 ON_RESUME 事件,此时,生命周期中的可见组件且位于前台时需要运行的任何功能。
例如:
当发生中断事件时,Activity 进入“Pause”状态,系统调用 onPause();- 如果 Activity 从“Pause”状态返回“Resume”状态,系统将再次调用 onResume() 方法。因此,您应实现 onResume(),以初始化在 onPause() 期间释放的组件,并执行每次 Activity 进入“onResume”状态时必须完成的任何其他初始化操作。
这里有个疑问,那么什么是”感知型组件“呢?下面我们来了解一下,如下code是我在新版本的AppcompatActivity(>26.1.0)写的,比较简单,也方便。
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity_layout);
myObserve = new MyObserve();
//在Activity中是没有getLifecycle方法,仅在AppCompatActivity使用
getLifecycle().addObserver(myObserve);
}
public class MyObserve implements LifecycleObserver{
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void initialize(){
android.util.Log.d(TAG,"MyObserve RESUME");
}
}
当前执行onResume方法时,则会紧接着执行initialize()方法;
TestActivity: onResume:
TestActivity: =============>initialize
6. Lifecycle是什么
- 其实Lifecycle是声明生命周期的观察者类,也是为了缩小Activity的代码量,啥意思呢,就是把Activity中生命周期的方法延伸给另外一个类,也就是和activity的生命周期关联上。
- 如果不使用AppCompatActivity的话,怎么使用Lifecycle添加Observe,答案可以,不过需要我们自己实现LifecycleOwner并Registry,下面来看一部code。
注册LifecycleObserver
public class MyActivityObserve implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate() {
android.util.Log.d("TestActivity", "=============>onCreate");
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
android.util.Log.d("TestActivity", "=============>onResume");
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
android.util.Log.d("TestActivity", "=============>onPause");
}
}
绑定Activity生命周期
public class TestActivity extends Activity implements LifecycleOwner {
private MyActivityObserve myObserve;
private LifecycleRegistry mLifecycleRegistry;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_main);
myObserve = new MyActivityObserve();
mLifecycleRegistry = new LifecycleRegistry(this);
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
mLifecycleRegistry.addObserver(myObserve);
}
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
@Override
protected void onResume() {
super.onResume();
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
}
@Override
protected void onPause() {
super.onPause();
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
}
}
启动acitvity
10-23 07:29:15.507 21936 21936 D TestActivity: =============>onCreate
10-23 07:29:15.514 21936 21936 D TestActivity: =============>onResume
点击home键
10-23 07:31:27.195 21936 21936 D TestActivity: =============>onPause
- 通过如上code,我们知道了是如何通过Lifecycle 对Activity生命周期一一绑定;
如果有多个类似的需要响应生命周期的类,Activity的生命周期函数就会变得非常臃肿,因此,Lifecycle就是为了解决这个痛点,将生命周期的响应分发到各个观察者中去,代码量蹭蹭就下来了。如:音视频播放、图片加载,这些吃内存大户,都应该响应生命周期,及时释放内存,否则很可能就会造成OOM;- 还有一种是通过mLifecycleRegistry.markState(Lifecycle.State.ON_CREATE)进行注册实现,实现方式只需将mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)更改即可,关于State相关状态就不详解了,可参考如下链接:
链接地址https://developer.android.com/reference/androidx/lifecycle/Lifecycle.State?hl=zh-cn#ON_RESUME
7. Activity生命周期onPause和onStop
- onPause
当用户要立开当前Activity时,执行onPause,但是这并不会销毁当前activity,当 Activity 进入已暂停状态时,与 Activity 生命周期相关联的所有生命周期“感知型组件”都将收到 ON_PAUSE 事件。这时,生命周期组件可以停止在组件没有位于前台时,无需运行的任何功能,例如停止相机,视频播放,等等。
onPause() 执行非常简单,而且不一定要有足够的时间来执行保存操作。不建议使用 onPause() 来保存应用或用户数据、进行网络调用或执行数据库等相关操作。因为在该方法完成之前,此类工作可能无法完成。相反,应该在 执行onStop() 期间执行高负载的关闭操作。
onPause()方法的完成并不意味着 Activity 离开“已暂停”状态。相反,Activity 会保持此状态,直到其恢复或变成对用户完全不可见。如果 Activity 恢复,系统将再次调用 onResume(),如果 Activity 从“已暂停”状态返回“已恢复”状态,系统会让 Activity 实例继续驻留在内存中,并会在系统调用 onResume() 时重新调用该实例。在这种情况下,您无需重新初始化在任何回调方法导致 Activity 进入“已恢复”状态期间创建的组件。如果 Activity 变为完全不可见,系统会调用 onStop()。- onStop()
Activity 不再对用户可见,也就是说已进入“已停止”状态,因而系统将调用 onStop() 。例如,当新启动的 Activity 覆盖整个屏幕时,会出现onStop这种情况。
如果 Activity 已结束运行并即将终止,系统还可以调用 onStop(),当 Activity 进入已停止状态时,与 Activity 生命周期相关联的所有生命周期“感知型组件“都将收到 ON_STOP 事件。
在 onStop() 方法中,应用应释放或调整在应用对用户不可见时的无用资源。例如,应用可以暂停动画效果、CPU 相对密集的关闭操作、信息保存到数据库、或从精确位置更新切换到粗略位置更新等。
当 Activity 进入“已停止”状态时,Activity 对象会继续驻留在内存中:该对象将维护所有状态和成员信息,但不会附加到窗口管理器。Activity 恢复后,Activity 会重新调用这些信息。您无需重新初始化在任何回调方法导致 Activity 进入“已恢复”状态期间创建的组件。系统还会追踪布局中每个 View 对象的当前状态,如果用户在 EditText 微件中输入文本,系统将保留文本内容,因此您无需保存和恢复文本。
8. Activity生命周期onDestroy()
onDestroy()销毁 Ativity 之前调用,系统会先调用 onDestroy(),那么为什么会调用呢?如下两点:
a.Activity 即将结束(由于用户彻底关闭 Activity 或由于系统 Activity 调用 finish());
b.由于配置变更(例如设备旋转或多窗口模式),系统暂时销毁 Activity;
当 Activity 进入已销毁状态时,与 Activity 生命周期相关联的所有生命周期"感知型组件"都将收到 ON_DESTROY 事件。这时,生命周期组件可以在 Activity 被销毁之前清理所需的任何数据。
onDestroy这里就不多说了,也是Activity最后一个生命周期;
四、Activity 总结
1. Activity状态
在这里需要说一下,系统会在需要释放 RAM 时终止进程;系统终止给定进程的可能性取决于当时进程的状态。反之,进程状态取决于在进程中运行的 Activity 的状态;
注:系统永远不会直接终止 Activity 以释放内存,而是会终止 Activity 所在的进程。系统不仅会销毁 Activity,还会销毁在该进程中运行的所有其他内容。
2. Activity生命周期总结
如下图是Activity生命周期7个方法:
Activity对应的生命周期方法及描述 :
3. 总结
当Activity启动时,依次会调用onCreate()–>onStart()–>onResume(),而当Activity退居后台时(不可见,点击Home或者被新的Activity完全覆盖),onPause()和onStop()会依次被调用。
当Activity重新回到前台(从桌面回到原Activity或者被覆盖后又回到原Activity)时,onRestart()–>onStart()–>onResume()会依次被调用。当Activity退出销毁时(点击back键),onPause()–>onStop()–>onDestroy()会依次被调用,到此Activity的整个生命周期方法回调完成。
综上:就是Activity整个典型的生命周期过程