文章目录
Activity的生命周期
一.返回栈
- 在Android当中Activity是可以进行重叠的,我们每次启动一个新的Activity,就会覆盖在原先的Activity之上,然后点击Back键就会销毁最上面的Activity,下面的Activity就会显示出来.
- 在Android当中使用任务(task)来管理Activity,一个任务就是一组存在栈里的Activity的集合,这个栈也被称作为返回栈(back stack)
- 当我们启动一个新的Acticity的时候,这个Activity就会处于这个返回栈的栈顶,当我们点击back销毁一个栈的时候,就会将栈顶的Activity进行出栈
二.Activity状态
- 每个Activity在其生命周期中最多可能会存在4中状态:运行状态,暂停状态,停止状态,销毁状态
1.运行状态
- 当一个Activity位于返回栈的栈顶的时候,Activity就会存在运行状态.
2.暂停状态
- 当一个Activity不在处于栈顶,但是它又是可见的情况下,Activity就进入了暂停状态.
- 既然Activity已经不在栈顶的位置了,那为什么还是可见的呢?因为并不是每一个Activity都会占满整个屏幕,比如对话框形式的Activity只会占用屏幕中间的部分
- 处在暂停状态的Activity仍然是完全存活的,系统也不愿意去回收这种类型的Activity,因为直接回收可见的Activity就相当于页面直接消失了内容,这种情况十分影响用户的体验.
- 只有在内存极低的情况下才会考虑回收这种类型的Activity
3.停止状态
- 当一个Activity不再处于栈顶的位置,而且完全不可见的情况下,这个时候Activity就进入了停止状态.
- 系统仍然会给这种Activity保存相应的状态和成员变量,但是这种是不太靠谱的,因为当有其他地方需要内存但是内存不够用的情况下,就会将这种Activity进行回收.
4.销毁状态
- 一个Activity从栈中移除之后,就变成了销毁状态,系统最倾向于回收处于这种状态的Activity,以此来保证手机内存的充足.
三.Activity的生存期
- 在Activity类当中定义了7个回调方法,覆盖了Activity生命周期的每一个环节
onCreate()
- 该方法会在Activity第一次被创建的时候进行调用,在该方法当中可以完成对Activity的初始化,比如加载布局,绑定事件等等.
onStart()
- 这个方法在Activity中由不可见变为可见的时候进行调用
onResume()
- 这个方法用于Activity准备好和用户进行交互的时候进行调用.此时的Acticity一定位于返回栈的栈顶位置,并且处在运行状态.
onPause()
- 这个方法在系统准备去启动或者恢复另外一个Activity的时候进行调用.我们通常会在这个方法当中将一些消耗CPU的资源释放掉,以此来保存一些关键性的数据,但是这个方法的执行速度一定要快,不然会影响到新的栈顶Activity的使用.
onStop()
- 这个方法在Activity完全不可见的时候进行调用,它和onPause()方法的区别在于,如果启动的新Activity是一个对话框式Activity,那么onPause()方法会得到执行,而onStop()方法不会被执行
onDestroy()
- 这个方法在Activity被销毁之前进行调用,之后Activity的状态将变成为销毁状态
onRestart()
- 这个方法在Activity由停止状态变为运行状态之前进行调用,也就是说Acticity被重新进行启动了
在以上的七个方法当中,除了onRestart()方法,其他都是两两相对的,从而可将Activity分成以下三种生存期
完整生存期
- Activity在onCreate()方法和onDestroy()方法之间所经历的就是完整生存期,一般情况下,Activity会在onCreate()方法中完成各种初始化的操作,在onDestroy()方法当中完成释放内存的各种操作.
可见生存期
- Activity在onStart()和onStop()方法之间经历的过程就是可见生存期,在可见生存期当中,Activity对于用户总是可见的.
- 即便可能无法和用户进行直接的交互,但是通过这两方法可以合理的管理那些对用户可见的资源
- 比如在onStart()方法中对资源进行加载,在onStop()方法当中对资源进行释放.从而保证处于停止状态的Activity不会占用过多的内存
前台生存期
- Activity在onResume()方法和onPause()方法之间的经历就是前台生存期
- 在前台生存期内Activity总是处在运行状态,此时Activity是可以和用户进行交互的
Activity的生命周期图
体验Activity的生命周期
编写三个对应的Activity
normal_activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is a dialog activity" />
</LinearLayout>
package com.zb.activitylifecycletest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class NormalActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.normal_layout)
}
}
dialog_activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is a dialog activity" />
</LinearLayout>
package com.zb.activitylifecycletest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class DialogActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.dialog_layout)
}
}
在AndroidManifest.xml中设置DialogActivity的主题为对话框式的主题
<activity
android:name=".DialogActivity"
android:theme="@style/Theme.AppCompat.Dialog"
android:exported="false" />
<activity
main_activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/startNormalActivity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start NormalActivity" />
<Button
android:id="@+id/startDialogActivity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start DialogActivity" />
</LinearLayout>
package com.zb.activitylifecycletest
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private val tag = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(tag, "onCreate")
setContentView(R.layout.activity_main)
startNormalActivity.setOnClickListener {
val intent = Intent(this, NormalActivity::class.java)
startActivity(intent)
}
startDialogActivity.setOnClickListener {
val intent = Intent(this, DialogActivity::class.java)
startActivity(intent)
}
}
override fun onStart() {
super.onStart()
Log.d(tag, "onStart")
}
override fun onResume() {
super.onResume()
Log.d(tag, "onResume")
}
override fun onPause() {
super.onPause()
Log.d(tag, "onPause")
}
override fun onStop() {
super.onStop()
Log.d(tag, "onStop")
}
override fun onDestroy() {
super.onDestroy()
Log.d(tag, "onDestroy")
}
override fun onRestart() {
super.onRestart()
Log.d(tag, "odRestart")
}
}
- 在MainActivity中的onCreate方法中设置了两个点击事件,点击第一个按钮会启动NormalActivity,点击第二个按钮会启动DialogActivity,然后再Activity的7个回调方法中分别用日志输出相关的内容
- 这样就可以通过观察日志的方法老观察Activity的生命周期了.
Activity被回收了怎么办
- 当一个Activity进入了停止状态,是有可能会被系统回收的.
- 假如现在一个应用当中有一个ActivityA,用户在ActivityA的基础上启动了ActivityB,那么ActivityA就进入了停止状态,这个时候由于系统内存空间不足,将Activity回收掉了
- 然后用户按下Back键后,其实还是会正常进行显示的,只不过就是这个时候并不会调用onRestart()方法,而是会执行ActivityA的onCreate()方法,因为在这种情况下Activity需要被重新创建一次
- 但是存在一个重要的问题不能够忽略:ActivityA中是有可能存在临时数据和状态的.当这个Activity由于内存不足被回收了会导致临时数据造成丢失.
- 如果我们的应用造成了临时数据的丢失实际上是比较影响用户体验的,所以需要我们想想办法来解决这个问题
- 在Activity中还提供了一个方法叫做onSaveInstanceState()回调方法,这个方法可以保证在Activity被回收之前一定会被调用,因此可以通过这个方法来解决问题.
onSaveInstanceState()方法
- 该方法会携带一个Bundle类型的参数,Bundle提供了一系列的方法用来保存数据,比如可以使用putString()方法来保存字符串,putInt()来保存整形数据.
- 每个保存数据的方法都采用键值对的方式,一个参数是键,用于后面从Bundle中取值,第二个参数就是我们要保存的值
- 在MainActivity中重写onSaveInstanceState()方法
//在Activity被回收之前保存相关数据
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val tempData = "Something you just typed"
outState.putString("data_key", tempData)
}
- 这个时候数据已经保存下来了,那我们应该在那里进行数据的恢复呢?
- 其实在我们一直使用的onCreate()方法的参数当中就有一个Bundle类型的参数,一般情况下这个参数都是为null的,但是当Activity被系统回收之前,开发人员通过onSaveInstanceState()方法保存的数据之后,onCreate()方法这个参数就会带有之前保存的全部数据.然后我们只需要通过相应的方法取出我们保存的值即可
- 在onCreate()方法中通过Bundle参数取出保存的数据
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState != null) {
val tempData = savedInstanceState.get("data_key")
Log.d(tag, "tempData is $tempData")
}
}