Android学习之活动的生命周期

 

•返回栈

  Android 中的活动是可以叠层的,我们每启动一个新的活动,就会覆盖在原活动之上,

  然后点击 Back 键会销毁最上面的活动,下面一个活动就会重新显示出来;

  其实 Android 是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack);

  栈是一种后进先出的数据结构,在认情况下,每当我们启动了一个新的活动,它会在返回栈中入栈,并处于栈顶的位置;

  而每当我们按下 Back 键或者调用 finish() 方法去销毁一个活动时,处于栈顶的活动会出栈,

  这时,前一个入栈的活动就会重新处于栈顶位置,系统总是会显示栈顶的活动给用户

•活动的状态

  • 运行状态
    • 一个活动位于返回栈的栈顶时,这时活动就处于运行状态
    • 系统最不愿意回收的就是处于运行状态的活动,因为这会带来非常差的用户体验
  • 暂停状态

    • 一个活动不再处于栈顶位置,但仍然可见时,这时活动就进入了暂停状态
    • 比如对话框形式的活动只会占用屏幕中间的部分区域,你还可以看到后边的界面
    • 这时,后面的活动就处于暂停状态
  • 停止状态

    • 一个活动不在处于栈顶位置,并且完全处于不可见的时候,就进入了停止状态
    • 系统仍然会为这种活动保存相应的状态和成员变量,但是这并不是完全可靠的
    • 当其他地方需要内存时,处于停止状态的活动有可能会被系统回收
  • 销毁状态

    • 一个活动从返回栈中移除后就变成了销毁状态
    • 系统倾向于回收处于这种状态的活动,从而保证手机内存充足

•活动的生存期

  Activity 类中定义了七个回调方法,覆盖了活动生命周期的每一个环节;

  •  onCreate() 

    • 每个活动中都重写这个方法,他会在活动第一次被创建的时候调用
    • 你应该在这方法中完成活动的初始化操作,比如加载布局、绑定事件等
  •  onStart() 

    • 这个方法在活动由不可见变为可见的时候调用
  •  onResume() 

    • 这个方法在活动准备好和用户进行交互时调用
    • 此时的活动一定位于返回栈的栈顶,并且处于运行状态
  •  onPause() 

    • 这个方法在系统准备去启动或者恢复另一个活动的时候调用
    • 我们通常会在这方法中将一些消耗 cpu 的资源释放掉以及保存一些关键数据
  •  onStop() 

    • 这个方法在活动完全不可见的时候调用
    • 它和  onPause()  方法的区别在于,如果启动的新活动是一个对话框样式的活动
    • 那么  onPause()  方法会执行, onStop()  方法不会执行
  •  onDestroy() 

    • 这个方法在活动被销毁之前调用
    • 之后活动的状态将变为销毁状态
  •  onRestart() 

    • 这个方法在活动由停止状态变为运行状态之前调用
    • 也就是活动被重新启动了
  以上七个方法除了  onRestart()  方法,其他都是两两相对的,从而又可以将活动分为三种生存期;
  • 完整生存期

    • 活动在  onCreate()  方法和  onDestroy()  方法之间所经历的就是完整生存期
    • 一般情况下,一个活动会在  onCreate()  方法中完成各种初始化操作
    • 而在  onDestroy()  方法中完成释放内存的操作
  • 可见生存期

    • 活动在  onStart()  方法和  onStop()  之间所经历的就是可见生存期
    • 在可见生存期内,活动对于用户总是可见的,即便有可能无法和用户进行交互
  • 前台生存期

    • 活动在  onResume()  方法和  onPause()  方法之间所经历的就是前台生存期
    • 这个生存期内,活动总是处于运行状态
    • 此时的活动是可以和用户进行相互的,我们平时看到和接触最多的也是这个状态下的活动

活动生命周期示意图

•体验活动的生命周期

准备工作

  新建一个项目,命名为 ActivityLifeCycleTest,并选择 Empty Activity;

  进入项目,将模式结构改成 Project 结构;

  接下来,我们需要额外新建两个 Empty Activity;

  右击  com.example.activitylifecycle -> New -> Activity -> Empty Activity ;

  新建的两个 Activity 分别命名为 normalActivity 和 DialogActivity;

  接下来就是敲代码的环节了;

activity_normal.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="this is a normal activity"
        android:textSize="20sp"
        android:layout_centerInParent="true"/>
</RelativeLayout>

activity_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="this is a dialog activity"
        android:textSize="20sp"
        android:layout_centerInParent="true"/>

</RelativeLayout>

  通过代码可以看出,这两个布局文件代码几乎没有区别,只是显示文字不同;

  其实从名字上可以看出,这两个 Activity 一个表示普通活动,一个表示对话框活动;

  但我们并没有对  .java  文件任何修改,在哪里体现出 DialogActivity 为对话框活动呢?

  别着急,下面我们马上开始配置;

  打开 AndroidManifest.xml 文件

  有没有发现什么不一样的?

  没错,在  .DialogActivity 的配置中;

  通过使用  android:theme="@style/Theme.AppCompat.Dialog" 将 DialogActivity 设置成对话框形式的主题

  接下来,我们修改 activity_main.xml 中的布局;

activity_main.xml

<?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:padding="10dp"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start normal Activity"
        android:textAllCaps="false"/>

    <Button
        android:id="@+id/btn_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start Dialog Activity"
        android:textAllCaps="false"/>

</LinearLayout>

  可以看到,在该布局中加入了两个按钮;

  btn_1 用于启动 normalActivity,btn_2 用于启动 DialogActivity;

  最后修改 MainActivity.java 中的代码

MainActivity.java

public class MainActivity extends AppCompatActivity {

    public static final String TAG = "MainActivity";
    private Button btn1;
    private Button btn2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate: ");

        btn1 = findViewById(R.id.btn_1);
        btn1.setonClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,normalActivity.class);
                startActivity(intent);
            }
        });
        btn2 = findViewById(R.id.btn_2);
        btn2.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 onRestart() {
        super.onRestart();
        Log.d(TAG, "onRestart: ");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: ");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop: ");
    }
}

  在  onCreate() 方法中,分别为两个按钮注册了点击事件,用于启动 normalActivity 和 DialogActivity;

  然后在 Activity 的 7 个回调方法中分别打印一句话,这样我们就可以通过观察日志的方式来更直观的理解活动的生命周期;

  有关 Log 的用法,请参考我的这篇博客

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...