简介
先说下什么是Activity?Activity是Android应用的关键组件,它提供了用户与应用进行交互的窗口,开发者可以通过这个窗口对界面进行绘制,展示用户需要的信息。通常,一个Activity实现应用中的一个屏幕。例如一个Activity实现“商品详情”页面,一个Activity实现“商品列表”页面。大多数应用包含多个屏幕,也就是包含多个Activity。通常,应用中的一个Activity会被指定为主Actvity,这就是用户启动应用时出现的第一个屏幕。一个Activity还可以启动另外一个Activity,例如从“商品列表”选择一个商品跳转到“商品详情”。
要想在应用中使用Activity,就必须在AndroidManifest.xml,也叫应用清单文件中使用<Activity></Activity>标签对Activity进行声明,指定需要的属性。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidtest">
<application
android:name=".BaseApplication"
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=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"
android:label="secondActivity">
</activity>
</application>
</manifest>
那么什么是Activity的生命周期呢?生命周期是指一个Activity从创建到销毁的过程,Activity提供了一系列的回调方便我们来处理各种生命周期中各种状态之间的转换,下面有一个流程图,介绍了Activity状态转换的过程:
流程图:
image从Activity的启动开始,Activity的创建会执行下边一系列的回调:
onCreate()[创建,不可见]--->onStart()[可见,不可交互]--->onResume()[可见,可交互],在resume的状态时,这个Activity就可以与用户进行交互,比如常见的点击、手指上下滑动,捏合等。
Activity创建之后,用户不会一直停留在这个页面,当遇到以下几种情况时,Activity的状态就可以改变,下面对流程图进行说明:
-
最右边的流程:
当启动另外一个Activity或者按home键进入后台的时候,Activity从可见变为不可见状态,这个时候会依次执行以下回调
onPause()[可见,不可交互]--->onStop()[不可见,不可交互]
我们可以看一下这个时候log打印日志, 日志我省略了无关的信息
D/test: 页面1 onCreate D/test: 页面1 onStart D/test: 页面1 onResume D/test: 跳转到页面2 D/test: 页面1 onPause D/test: -----页面2 onCreate D/test: -----页面2 onStart D/test: -----页面2 onResume D/test: 页面1 onSaveInstanceState D/test: 页面1 onStop
-
中间的流程:
当用户点击返回按钮的时候, 我们调用Activity的finish()方法,然后Activity销毁,这属于一种正常的销毁。如图中中间的流程,会依次执行以下回调:
onPause()[可见,不可交互]--->onStop()[不可见,不可交互]--->onDestory()[销毁]
这个时候的log日志如下, 页面2的流程
D/test: -----页面2 点击返回 D/test: -----页面2 onPause D/test: 页面1 onRestart D/test: 页面1 onStart D/test: 页面1 onResume D/test: -----页面2 onStop D/test: -----页面2 onDestroy
-
最左边的流程:
当系统配置改变(例如屏幕旋转 ), 或者Activity在后台,前台的Activity需要更多资源的时候,系统就必须关闭后台进程来恢复内存,这个时候系统就有可能销毁这个Activity,这种情况就属于非正常销毁。如果要模拟非正常销毁的过程,可以打开手机设置里--开发者选项--不保留活动开关。这种情况下,Activity被销毁之后,当用户再次唤醒这个Activity的时候,Activity就会被系统重建,下面是系统销毁到重建的执行流程:
onPause--->onStop--->onDestory--->onCreate--->onStart--->onResume()
同样我们看下这个时候log日志,我使用旋转屏幕来模拟了下系统销毁到创建的过程
D/test: 页面1 onCreate D/test: 页面1 onStart D/test: 页面1 onResume D/test: Application onConfigurationChanged D/test: 页面1 onPause D/test: 页面1 onSaveInstanceState D/test: 页面1 onStop D/test: 页面1 onDestroy D/test: 页面1 onCreate D/test: 页面1 onStart D/test: 页面1 onResume
生命周期中的各种回调
下面详细介绍一下Activity的每种回调,大家可以再看一下流程图,想想都有哪些回调,这些回调有什么区别?
-
onCreate(@Nullable Bundle savedInstanceState),创建Activity触发,它的下一个回调是onStart()
- 要创建一个Activity,就必须实现此回调,在Activity首次创建的时候会触发该回调, 表明Activity进入“已创建 ”的状态。
- 在Activity整个生命周期中,onCreate只会发生一次,我们可以在onCreate方法中执行应用的启动逻辑,例如绑定viewmodel,初始化页面等。onCreate方法有一个Bundle类型的参数savedInstanceState,保存了Activity销毁前的状态。
- 假如Activity被非正常销毁了,比如说配置改变或者内存不足的情况下,就会被销毁,在销毁的时候,系统会调用onSaveInstanceState()回调, 我们可以在onSaveInstanceState()回调中保存想要保存的数据,在页面重新创建的时候依然还会执行onCreate()回调,那么我们就可以从savedInstanceState去获取我们保存的值。这里说明一下,如果Activity是首次创建,那么savedInstanceState为null。
//以下示例代码演示了在onSaveInstanceState如何保存数据,以及在onCreate中如何获取保存的数据: //实例中我保存了一个key为isCreate的值 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState != null) { //在这里获取数据 Log.d("test", String.valueOf(savedInstanceState.getBoolean("isCreated"))); } } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); //在这里保存数据 outState.putBoolean("isCreated", true); }
Activity中View的状态如何保存呢,什么叫View的状态,比如说我们
-
onStart(),下一个回调是onResume()
该回调是在onCreate之后调用的,表明Activity已进入“已开始”状态,页面此时进入可见状态,但是不在前台,此时还不能交互。onStart()当页面被唤醒的时候会被调用,所以它可以被调用多次
-
onResume(),当Activity进入后台的时候,就会调用onPause()回调
该回调是在onStart之后调用的,表明Activity已进入“已恢复”状态,用户回到前台,用户可以与应用进行交互。onResume()回调会被执行多次,因为每次唤醒之后都会执行这个回调。
Activity创建之后就会一直维持这个状态,直到遇到跳转到其他页面,退入后台等中断事件的发生,Activity就退居后台,不再与用户进行交互,接下来就会进入onPause()回调
-
onPause(),下一个回调是onStop
调用该回调的时候表示用户正在离开此Activity, Activity失去了焦点, 进入“已暂停”状态, 这个时候 Activity依然可见,但是不可与用户进行交互。如上边流程图中的的点击返回调用finish、home键退入后台或者打开另外一个Activity。
onPause()的执行非常简单,而且不一定有足够的时间来执行保存操作,所以,我们不应该用onPause()来保存数据,执行网络请求,或者数据库相关操作,而使用onStop方法来执行这些操作
-
onStop()
在onPause之后调用,表示Activity进入不可见状态,也就是“已停止”状态
-
onDestory(), 表示Activity被销毁
在Activity销毁之前,系统会先调用onDestory()回调, 系统调用onDestory的原因下面几种,可以使用isFinishing()来区分
- 用户点击了返回按钮,Activity 通过调用finish方法进行返回, 这种情况下的销毁属于用户期望的行为,所以Activity是彻底销毁了,Activity关联的viewModel也会调用onCleared()方法,销毁数据, isFinishing = true
- 系统配置变更(例如设备旋转)或者内存压力,系统会暂时销毁Activity,销毁之后当用户唤醒的时候,系统就会创建一个新的Activity,这种非正常销毁,它的viewModel是不会销毁的,viewModel会被传递给重新创建的Activity,所以我们可以用viewModel来保存我们视图相关的数据 ,这种情况下Activity的 isFinishing = false
Activity被销毁又重建的这种情况下,有一个问题,我们该如何保存View的状态呢?
首先说一下我们为什么要保存View的状态呢?
比如有一个非常复杂的表格页面,需要用户填各种信息,有非常多的文字输入控件,多选框,开关等,但是当用户花了十几分钟终于把页面填完了,这个时候不小心旋转了下屏幕,上边说过,如果配置改变了,页面是会被销毁重建的,那么此时所有填的信息就丢失了,很可怕吧。下面演示了这种情况, 当我们没有EditText设置id的时候,旋转屏幕之后,里边编辑的内容就丢失了:
image这个时候我们就需要去保存View的状态,保证页面被重新创建的时候View操作的内容依然存在
系统只会保存页面中我们指定过ID的view状态,系统恢复状态时会根据ID找到对应的view去恢复对应的状态,所以我们在创建view的时候,如果想让系统保存它的状态,就一定要设置ID
网友评论