活动的生命周期
返回栈
-
Android中的活动是可以层叠的。我们每启动一个新的活动,就会覆盖在原活动之上,然后点击Back键会销毁最上面的活动,下面的活动就会重新显示出来
-
Android其实是使用(Task)来管理系统的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack)。栈是一种后进先出的数据结构,在默认情况下,每当我们启动了一个新的活动,他会在返回栈中入栈,并处于栈顶的位置。每当按下Back键或者调用finish()方法去销毁一个活动时,处于栈顶的活动会出栈,这时前一个活动就会重新处于栈顶的位置。系统总是会将处于栈顶的活动显示给用户。
-
返回栈工作示意图
活动状态
- 运行状态:当一个活动位于返回栈的栈顶时,这时活动就处于运行状态。系统最不愿意回收的就是处于运行状态的活动,因为这会带来非常差的用户体验
- 暂停状态:当一个活动不再处于栈顶位置,但仍然可见时,这时活动就进入了暂停状态
- 停止状态:当一个活动不再处于栈顶位置,并且完全不可见的时候,就进入了停止状态。系统仍然会为这种活动保存相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存是,处于停止状态的活动有可能会被系统回收
- 销毁状态:当一个活动从返回栈中移除后就变成了销毁状态。系统会最倾向于回收处于这种状态的活动,从而保证手机的内存充足
活动的生存期
#### Activity类中定义了7个回调方法,覆盖了活动生命周期的每一个环节
- onCreate():每个活动都重写了这个方法,它会在活动第一次被创建的时候调用,在这个方法中完成活动的初始化操作,比如加载布局、绑定事件等
- onStart():这个方法在活动由不可见变为可见的时候调用
- onResume():这个方法在活动准备好和用户进行交互的时候调用。此时的活动一定处于返回栈的栈顶,并处于运行状态
- onPause():这个方法在系统准备去启动或者恢复另一个活动的时候调用。通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用
- onStop():这个方法早活动完全不可见的时候调用。他和onPause()方法的主要区别在于,如果启动的新活动是一个对话框的活动,那么onPause()方法会得到执行,而onStop()方法并不执行
- onDestroy():这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态
- onRestart():这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了
以上7个方法中除了onRestart()方法,其他都是两两相对的,从而又可以将活动分为3种生存期:
- 完整生存期:活动在 onCreate()方法和onDestroy()方法之间所经历的,就是完整生存期。一般情况下在 onCreate()方法中完成各种初始化操作,而在onDestroy()方法中完成释放内存的操作
- 可见生存期:活动在onStart()方法和onStop()方法之间经历的,就是可见生存期。在可见生存期内,活动对于用户总是可见的,即便有可能无法和用户进行交互。我们可以通过这两个方法,合理的管理那些对用户可见的资源。比如在onStart()方法中对资源进行加载,而在onStop()方法中对资源进行释放,从而保证处于停止状态的活动不会占用过多内存
- 前台生存期:活动在onSesume()方法和onPause()方法之间所经历的就是前台生存期。在前台生存期内,活动总是处于运行状态的,此时的活动是可以和用户进行狡猾的,我们平时看到和接触最多的也就是这个状态下的活动
- 活动生命周期示意图
实例
//注册页面AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.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/Theme.ActivityLifeCycleTest">
<!-- android:theme 用于给当前活动指定主题 这里是让DialogActivity活动使用对话框的主题-->
<activity android:name=".DialogActivity" android:theme="@style/Theme.AppCompat.Dialog">
</activity>
<activity android:name=".NormalActivity" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
//应用布局activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<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>
//正常布局normal_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is a normal activity"/>
</LinearLayout>
//对话框布局dialog_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is a dialog activity"
/>
</LinearLayout>
//正常布局活动 NormalActivity
package com.example.activitylifecycletest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class NormalActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.normal_layout);
}
}
//对话框活动DialogActivity
package com.example.activitylifecycletest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class DialogActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_layout);
}
}
//应用活动MainActivity
package com.example.activitylifecycletest;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("TAG", "onCreate");
setContentView(R.layout.activity_main);
Button startNormalActivity = (Button) findViewById(R.id.start_normal_activity);
Button startDialogActivity = (Button) 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 intent1 = new Intent(MainActivity.this,DialogActivity.class);
startActivity(intent1);
}
});
}
@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");
}
//总结
//点击第一个按钮启动NormalActivity
//当MainActivity第一次被创建时 先执行onCreate()、onStart()、onResume(),
//点击第一个按钮,NormalActivity将MainActivity完全遮住,因此onPause()和onStop()得到执行
//然后按下Back键,返回MainActivity,之前MainActivity已经进入了停止状态,所以onRestart()方法得到执行之后又依次执行onStart()和onResume()方法
//注意:onCreate()没有被执行是因为MainActivity没有被重新创建
//点击第二个按钮,启动DialogActivity
//DialogActivity并没有将MainActivity完全覆盖,MainActivity只是进入了暂停状态,并没有进入停止状态,所以只执行onPause()方法
//按下Back键返回MainActivity也只有onResume()方法执行
//在MainActivity按Back键,会依次执行onPause()、onStop()、onDestroy(),最终销毁MainActivity
}
活动被回收了怎么办
-
当一个活动进入到停止状态,是有可能被回收的
-
比如:有一个活动A,在A的基础上启动活动B,A就会进入停止状态,这个时候由于内存不足,将A回收掉了,这是用户按Back键返回活动A。这时还是会正常显示A,只不过不会执行onRestart()方法,而是会执行活动A的onCreate方法,因为在这种情况下,活动A会被重新创建一次
-
上述例子有一个重要问题,活动A中可能存在临时数据和状态,比如:MainActivity有一个文本输入框,现在你输入了一段文字,然后启动NormalActivity,这时MainActivity因为内存不足被回收,过了一会你又点击了Back键返回到MainActivity,你会发现刚刚输入的内容不见了,这是因为MainActivity被重新创建了
-
Activity提供了一个onSaveInstanceState()回调方法,可以解决活动被回收临时数据得不到保存的问题
-
onSaveInstanceState()方法会携带一个Bundle类型的参数,Bundle提供了一系列的方法用于保存数据,比如可以使用putString()方法保存字符串,使用putInt()方法保存整型数据,以此类推
-
实例
package com.example.activitylifecycletest; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("TAG", "onCreate"); setContentView(R.layout.activity_main); if (savedInstanceState != null){ String tempData = savedInstanceState.getString("data_key"); Log.d("data_key", tempData); } Button startNormalActivity = (Button) findViewById(R.id.start_normal_activity); Button startDialogActivity = (Button) 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 intent1 = new Intent(MainActivity.this,DialogActivity.class); startActivity(intent1); } }); } @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"); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); String tempData = "Something you just typed"; outState.putString("data_key",tempData); } }