2.2.4 Activity的生命周期
Android系统中的“页面”(也就是Activity)的生命周期,与2.1.4节中介绍的HTML生命周期类似。图2-12为Android官方网站上的生命周期,图中已经较为清晰地表达了Android的Activity的生命周期流程。
图2-12 Activity的生命周期
表2-2为读者详细归纳了常用的6种生命周期状态:onCreate、onStart、onResume、onPause、onStop和onDestroy。
表2-2 Activity状态方法和具体用处
可能大家理解onPause和onStop这两个生命周期还有些困难,Activity被遮挡是一个什么样的页面状态呢?大家对此并没有很直观的感受,接下来我们先通过一个小例子来介绍一下onPause和onStop生命周期。
我们需要一个透明的Activity(TransparentActivity)来做onPause的遮挡实验,具体如代码清单2-14所示。
代码清单2-14 TransparentActivity实现
package com.example.chenchen.book; import android.app.Activity; import android.os.Bundle; public class TransparentActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.transparent); } }
上述代码其实是一个非常简单的Activity,但是可能有人会问:不是说遮挡的Activity吗?那应该是个透明的Activity或者展示一半的Activity?我们之前提到,项目中每添加一个新的Activity就要在AndroidManifest.xml文件中添加一个项目声明,如代码清单2-15所示。大家观察代码清单中第13行代码,即<activity android:theme="@android:style/Theme.Translucent" android:name=".TransparentActivity">,这行代码实际上除了声明TransparentActivity之外,还给这个Activity添加了一个主题(theme)——Theme.Translucent,它表示该Activity是一个全透明的Activity。
代码清单2-15 Activity的透明设置
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.chenchen.book"> <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"> </activity> <activity android:theme="@android:style/Theme.Translucent" android:name=".TransparentActivity"> </activity> <activity android:name=".AActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".BActivity"> </activity> </application> </manifest>
紧接着我们需要在之前创建的TransparentActivity中添加一个布局文件——transparent.xml,其具体功能实现如代码清单2-16所示。TransparentActivity的内容只有一行文字,主要是为了在展示该Activity时告诉用户:此Activity是透明的。
代码清单2-16 transparent.xml布局文件
<?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=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="我是透明的Activity" android:textSize="20sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
最后我们只需要更改一下代码清单2-12中的AActivity就可以完成这个实验了,具体更改之后的代码如代码清单2-17所示。首先我们在代码中加入了onPause和onStop这两个Activity中最常用的生命周期钩子,并且在对应的钩子中进行日志输出,紧接着添加了一个新的按钮事件,也就是button_toast按钮的事件,该事件完成了跳转透明Activity的操作。稍后将给大家演示onPause和onStop的触发操作。
代码清单2-17 添加跳转透明TransparentActivity之后的代码
package com.example.chenchen.book; import android.app.AlertDialog; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; public class AActivity extends AppCompatActivity { AActivity mContext = this; private AlertDialog.Builder builder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a); Button button = findViewById(R.id.toB); Button button_toast = findViewById(R.id.toast); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(AActivity.this,BActivity.class); mContext.startActivity(intent); } }); button_toast.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {Intent intent= new Intent(mContext, Trans-parentActivity.class); startActivity(intent); } }); } @Override protected void onPause() { Log.d("test_status","onPause"); super.onPause(); } @Override protected void onStop() { Log.d("test_status","onStop"); super.onStop(); } }
在代码编写完毕后,直接运行这个实例,然后就会看到图2-13所示界面。与之前图2-10中内容不一样的地方是,图2-13中又多了一个“弹出透明ACTIVITY”按钮。
图2-13 AActivity界面
紧接着我们按下这个按钮,就会看到如图2-14,所展示的界面了。在图2-14中,我们可以观察到在手机界面中间又出现了一行字:“我是透明的Activity”,但是也能看到“我是AActivity”字样,其实这是透明的TransparentActivity压在了AActivity上的结果。
图2-14 跳转到TransparentActivity展示
这时候让我们观察一下日志打印,可以在onPause钩子和onStop钩子中看到打印出来的日志,如图2-15所示。我们在日志中发现,随着透明Activity的出现,并没有触发原来AActivity的onStop钩子,而是仅仅触发了onPause钩子,这就是我们之前说到的部分遮挡,所谓部分遮挡不仅仅是一个不透明的Activity遮挡了一部分Activity的情况,还包括这种透明模板的Activity的遮挡情况,即不管开发者在界面上看到完全透明的TransparentActivity遮挡下面的AActivity,还是只看到部分AActivity被遮挡,都只会触发onPause钩子,而不会触发onStop钩子。
图2-15 点击弹出透明Activity日志输出
提示
很多人认为Android自带的Dialog弹层也会触发onPause钩子,因为Dialog也遮挡了Activity,但是实际上普通的Dialog的弹出是没有办法触发Activity的onPause钩子的。
那么onStop日志到底什么时候会出现呢?让我们先回到图2-13所示的界面,然后点击“跳转到B”按钮。然后观察一下控制台,就会看到如图2-16所示的输出日志。
图2-16 点击“跳转到B”按钮的日志输出
我们可以观察到控制台输出了一个onPause,紧接着输出了一个onStop。这就是BActivity(不透明的Activity)完全遮挡了AActivity,所以会触发onStop钩子。触发onStop的情况下就一定会触发onPause,因为完全遮挡之前,势必会先出现部分遮挡的状态,但是触发onPause的时候不一定会触发onStop。
Android端的Activity的生命周期就介绍完了,我们将在2.3节中进行一些前端与移动端页面属性以及生命周期的对比,并且提供微型电商的基础页面代码。