每一个活动在其生命周期中最多可能会有 4 种状态:java
一、运行状态android
当一个活动位于返回栈的栈顶时,这时活动就处于运行状态。系统最不肯意回收的就是处于运行状态的活动,由于这会带来很是差的用户体验。app
二、暂停状态ide
当一个活动再也不处于栈顶位置,但仍然可见时,这时活动就进入了暂停状态。你可能会以为既然活动已经不在栈顶了,还怎么会可见呢?布局
这是由于并非每个活动都会占满整个屏幕,好比对话框形式的活动只会占用屏幕中间的部分区域。处于暂停状态的活动仍然是彻底存活着的,系统也不肯意去回收这种活动(由于它仍是可见的,回收可见的东西都会在用户体验方面有很差的影响,)只有在内存极低的状况下,系统才会去考虑回收这种活动。this
三、中止状态spa
当一个活动再也不处于栈顶位置,而且彻底不可见的状态,就进入了中止状态。系统仍然会为这种活动保持相应的状态和成员变量,可是这并非彻底可靠的,当其余地方须要内存时,处于中止状态的活动有可能会被系统回收。code
四、销毁状态orm
当一个活动从返回栈种移除后就变成了销毁状态。系统会最倾向于回收处于这种状态的活动,从而保证手机的内存充足。xml
Activity 类中定义了 7 个回调方法,覆盖了 Activity 生命周期的每个环节:
onCreate()
这个方法你已经看到过不少次了,每一个活动中咱们都重写了这个方法,它会在活动第一次被建立的时候调用。你应该在这个方法中完成活动的初始化操做,好比加载布局、绑定事件等。
onStart()
这个方法在活动由不可见变为可见的时候调用。
onResume()
这个方法在活动准备好和用户进行交互的时候调用。此时的活动必定位于返回栈的栈顶,而且处于运行状态。
onPause()
这个方法在系统准备去启动或者恢复另外一个活动的时候调用。咱们一般会在这个方法中将一些消耗 CPU 的资源释放掉,以及保存一些关键数据,但这个方法的执行速度必定要快,否则会影响到新的栈顶活动的使用。
onStop()
这个方法在活动彻底不可见的时候调用。它和 onPause() 方法的主要区别在于,若是启动的新活动是一个对话框式的活动,那么 onPause() 方法会获得执行,而 onStop() 方法并不会执行。
onDestroy()
这个方法在活动被销毁以后调用,以后活动的状态将变为销毁状态。
onRestart()
这个方法在活动由中止状态变为运行状态以前调用,也就是活动被从新启动了。
以上 7 个方法中除了 onRestart() 方法,其余都是两两对应的,从而能够将活动分为 3 种生存期。
完整生存期:活动在 onCreate() 方法和 onDestroy() 方法之间所经历的,就是完整生存期。通常状况下,一个活动会在 onCreate() 方法中完成各类初始化操做,而在 onDestroy() 方法种完成释放内存的操做。
可见生存期():活动在 onStart() 方法和 onStop() 方法之间所经历的,就是可见生存期。在可见生存期内,活动对于用户老是可见的,即使有可能没法和用户进行交互。咱们能够经过这两个方法,合理地管理那些对用户可见的资源。好比在 onStart() 方法中对资源进行加载,而在 onStop() 方法中对资源进行释放,从而保证处于中止状态的活动不会占用过多内存。
前台生存期:活动在 onResume() 方法和 onPause() 方法之间所经历的,就是前台生存期。在前台生存期内,活动老是处于运行状态的,此时的活动是能够和用户进行交互的,咱们平时看到和接触最多的就是这个状态下的活动。
咱们看下官方给出的 Activity 生命周期的示意图:
咱们先定义一个:NormalActivity
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout 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" tools:context=".NormalActivity"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="This is a normal activity" /> </android.support.constraint.ConstraintLayout>
再定义一个:DialogActivity
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout 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" tools:context=".DialogActivity"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="This is a dialog activity" /> </android.support.constraint.ConstraintLayout>
为了让 DialogActivity 使用对话框式主题,咱们在 AndroidManifest.xml 中作以下设置:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.marco.activitylifecycletest"> <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=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".NormalActivity" /> <activity android:name=".DialogActivity" android:theme="@style/Theme.AppCompat.Dialog"> // Look here </activity> </application> </manifest>
接下来修改 activity_main.xml,从新定制主活动的布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/start_normal_activity" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Start NormalActivity" /> <Button android:id="@+id/start_dialog_activity" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Start DialogActivity" /> </LinearLayout>
修改 MainActivity :
package com.example.marco.activitylifecycletest; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { public static final String TAG = "MainActivity"; private Button startNormalActivity = null; private Button startDialogActivity = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startNormalActivity = findViewById(R.id.start_normal_activity); startDialogActivity = findViewById(R.id.start_dialog_activity); startNormalActivity.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, NormalActivity.class); startActivity(intent); } }); startDialogActivity.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, DialogActivity.class); startActivity(intent); } }); } @Override protected void onStart() { super.onStart(); Log.d(TAG, "onStart"); } @Override protected void onResume() { super.onResume(); Log.d(TAG, "onResume"); } @Override protected void onPause() { super.onPause(); Log.d(TAG, "onPause"); } @Override protected void onStop() { super.onStop(); Log.d(TAG, "onStop"); } @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy"); } @Override protected void onRestart() { super.onRestart(); Log.d(TAG, "onRestart"); } }
(1)当 MainActivity 第一次被建立时,以下方法被执行:
2018-10-18 04:31:29.071 2526-2526/? D/MainActivity: onCreate 2018-10-18 04:31:29.077 2526-2526/? D/MainActivity: onStart 2018-10-18 04:31:29.083 2526-2526/? D/MainActivity: onResume
(2)点击 Start NormalActivity 按钮:
2018-10-18 04:33:02.159 2526-2526/com.example.marco.activitylifecycletest D/MainActivity: onPause 2018-10-18 04:33:02.745 2526-2526/com.example.marco.activitylifecycletest D/MainActivity: onStop
由于 NormalActivity 已经把 MainActivity 彻底遮挡住,所以 onPause() 和 onStop() 方法都会获得执行。
(3)点击 Back 键返回 MainActivity:
2018-10-18 04:35:00.010 2526-2526/com.example.marco.activitylifecycletest D/MainActivity: onRestart 2018-10-18 04:35:00.012 2526-2526/com.example.marco.activitylifecycletest D/MainActivity: onStart 2018-10-18 04:35:00.014 2526-2526/com.example.marco.activitylifecycletest D/MainActivity: onResume
因为以前 MainActivity 已经进入了中止状态,因此 onRestart() 方法会获得执行,以后又会执行 onStart() 和 onResume() 方法。注意,此时 onCreate() 方法不会执行,由于 MainActivity 并无从新建立。
(4)点击 Start DialogActivity 按钮:
2018-10-18 04:43:38.006 3555-3555/com.example.marco.activitylifecycletest D/MainActivity: onPause
经过 Log 能够看到,只有 onPause() 方法获得了执行,onStop() 方法并无执行,这是由于 DialogActivity 并无彻底遮挡住 MainActivity,此时 MainActivity 只是进入了暂停状态,并无进入中止状态。
(5)点击 Back 键返回 MainActivity:
2018-10-18 04:50:12.222 3555-3555/com.example.marco.activitylifecycletest D/MainActivity: onResume
按下 Back 键返回 MainActivity 也应该只有 onResume() 方法会获得执行。
(6)在 MainActivity 界面按下 Back 键退出程序:
2018-10-18 04:51:47.673 3555-3555/com.example.marco.activitylifecycletest D/MainActivity: onPause 2018-10-18 04:51:48.013 3555-3555/com.example.marco.activitylifecycletest D/MainActivity: onStop 2018-10-18 04:51:48.015 3555-3555/com.example.marco.activitylifecycletest D/MainActivity: onDestroy
依次会执行 onPause()、onStop() 和 onDestroy 方法,最终销毁 MainActivity。
咱们在以前分析 Activity 的生命周期的时候曾经提到过:若是一个活动进入了 onStop (中止)状态,是有可能被系统回收的!
好比咱们看如下的场景:
应用中有一个活动 A ,用户在活动 A 的基础上启动了活动 B ,活动 A 就进入了中止的状态,这个时候因为系统内存不足,将活动 A 回收掉了,而后用户按下 Back 键返回活动 A ,会出现什么状况呢?
其实仍是会正常显示活动 A 的,可是此时并不会执行 onRestart() 方法了,而是会执行活动 A 的 onCreate() 方法,由于活动 A 在这种状况下会被从新建立一次。
可能这并不会影响正常的功能,可是存在一个特殊状况:若是活动 A 中存在临时数据和状态(好比 A 中有一个文本输入框,咱们输入了一些文字,而后启动了 B 活动,若是 A 被 kill了,在从新回到 A 后,A 活动从新建立,那么数据都丢失了),此时会严重影响用户体验,该怎么办?
其实官方文档给出了解决方案,Activity 中提供了一个 onSaveInstanceState() 回调方法,这个方法能够保证在活动被回收以前必定会被调用,所以咱们能够经过这个方法来解决活动被回收时临时数据得不到保存的问题。
onSaveInstanceState() 方法会携带一个 Bundle 类型的参数,Bundle 提供了一系列的方法用于保存数据,好比可使用 putString() 方法保存字符串,使用 putInt() 方法保存整型数据,依次类推。
每一个保存方法须要传入两个参数,第一个参数是键,用于后面从 Bundle 中取值,第二个参数是真正要保存的内容。
咱们如今对上面的代码进行修改,在 MainActivity 中添加以下代码将临时数据进行保存:
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); String tempData = "Something you just typed"; outState.putString("data_key", tempData); }
Ok,数据保存好了,那咱们应该在哪边进行恢复?
不知道你有没有发现,在 onCreate() 方法中有一个 Bundle 类型的参数。这个参数通常状况下是 null ,可是若是在活动被系统回收以前有经过 onSaveInstanceState() 方法来保存数据的话,这个参数就会带有以前所保存的所有数据,咱们只须要再经过相应的取值方法将数据取出便可。
修改 MainActivity 的 onCreate() 方法:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG, "onCreate"); if (savedInstanceState != null) { String tempData = savedInstanceState.getString("data_key"); Log.d(TAG, tempData); } ... ... }
经过上面的方法取出值以后再作相应的恢复操做就能够了,好比说将文本内容从新赋值到文本输入框上便可。