Android第6讲——Activity的生命周期

Android第6讲——Activity的生命周期

1、Activity的四种状态

一个Android应用,一般包括一个或多个Activity,有的Activity可以被用户直接操作,有的Activity则被其它Activity覆盖或遮挡,因而不能被用户直接操作。

为了对这些Activity进行管理,Android使用栈来保存这些Activity:处于栈顶的Activity可以直接被用户操作,不能直接被用户操作的Activity则不位于栈顶。

由此,Activity可以分为四种状态:

  • 运行状态:Activity位于栈顶;
  • 暂停状态:Activity不位于栈顶,但是位于其上的Activity没有完全挡住它;
  • 停止状态:Activity被其它Activity完全挡住;
  • 销毁状态:Activity从栈中被移除后进入销毁状态。

为了保证系统资源充足,系统会回收Activity,上述四种状态的Activity,系统最倾向于回收销毁状态的Activity、其次是回收停止状态的Activity,比较少回收暂停状态和运行状态的Activity。

2、Activity的与状态相关的回调方法

到现在为止,我们的主要功能在Activity的onCreate方法中添加,其实除了onCreate之外,还有六个类似的方法,它们是:

Android第6讲——Activity的生命周期

下面我们通过程序来深刻理解Activity的这些回调方法。

3、创建MyProject工程

我们创建一个名为MyProject的工程,并建立一个Empty Activity:

Android第6讲——Activity的生命周期

4、设计界面

这里使用LinearLayout布局,并放置两个按钮:

Android第6讲——Activity的生命周期

“拨打电话”按钮,用于显示拨打电话的界面,可以完全覆盖MainActivity;

“显示小活动”按钮,用于显示一个小的Activity,只能遮挡部分MainActivity。

这是MainActivity界面的完整代码:

<?xml version="1.0" encoding="utf-8"?><LinearLayout 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:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/button_dial" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="拨打电话" /> <Button android:id="@+id/button_dialog" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="显示小活动" /> </LinearLayout>5、增加小Activity

添加一个空Activity,命名为SmallActivity,然后在界面中加一个TextView:

Android第6讲——Activity的生命周期

注意,SmallActivity不能从AppCompatActivity派生,只能从Activity派生,否则运行会出异常。这是SmallActivity的源代码:

package com.flying.myproject;import android.app.Activity;import android.os.Bundle;public class SmallActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_small); } }

修改AndroidManifest.xml文件,将该Activity设置为Dialog主题。这是AndroidManifest.xml文件的内容:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.flying.myproject"> <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.MyProject"> <activity android:name=".SmallActivity" android:theme="@android:style/Theme.Dialog"> </activity> <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>6、编写两个按钮的点击事件处理代码

为了代码清晰,这里我们将MainActivity定义为实现View.OnClickListener接口的类。

加入两个按钮的点击事件处理功能后,MainActivity的代码如下:

package com.flying.myproject;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.view.View;import android.widget.Button;public class MainActivity extends AppCompatActivity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button dialButton = (Button)findViewById(R.id.button_dial); Button dialogButton = (Button)findViewById(R.id.button_dialog); dialButton.setOnClickListener(this); dialogButton.setOnClickListener(this); } public void onClick(View view){ Intent intent; switch (view.getId()){ case R.id.button_dial: intent = new Intent(Intent.ACTION_DIAL); intent.setData(Uri.parse("tel:95511")); startActivity(intent); break; case R.id.button_dialog: intent = new Intent(this, SmallActivity.class); startActivity(intent); break; default: break; } } }7、添加回调方法

现在,我们为MainActivity添加所有的回调方法,每个回调方法都插入一条日志记录语句。这是添加之后MainActivity的源代码:

package com.flying.myproject;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import java.util.Calendar;public class MainActivity extends AppCompatActivity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button dialButton = (Button)findViewById(R.id.button_dial); Button dialogButton = (Button)findViewById(R.id.button_dialog); dialButton.setOnClickListener(this); dialogButton.setOnClickListener(this); Log.d("MyTest", "onCreate is called."); } @Override protected void onStart(){ super.onStart(); Log.d("MyTest", "onStart is called."); } @Override protected void onStop(){ super.onStop(); Log.d("MyTest", "onStop is called."); } @Override protected void onResume(){ super.onResume(); Log.d("MyTest", "onResume is called."); } @Override protected void onPause(){ super.onPause(); Log.d("MyTest", "onPause is called."); } @Override protected void onDestroy(){ super.onDestroy(); Log.d("MyTest", "onDestroy is called."); } @Override protected void onRestart(){ super.onRestart(); Log.d("MyTest", "onRestart is called."); } public void onClick(View view){ Intent intent; switch (view.getId()){ case R.id.button_dial: intent = new Intent(Intent.ACTION_DIAL); intent.setData(Uri.parse("tel:95511")); startActivity(intent); break; case R.id.button_dialog: intent = new Intent(this, SmallActivity.class); startActivity(intent); break; default: break; } } }

可以看到,每个回调方法,都调用了Log.d方法来记录日志。

8、运行程序

现在,我们运行程序,程序启动后的界面为:

Android第6讲——Activity的生命周期

此时Logcat中,使用“MyTest”过滤后的日志为:

Android第6讲——Activity的生命周期

点击“拨打电话”按钮后,界面变为:

Android第6讲——Activity的生命周期

此时Logcat中的日志为(红框中为新增的日志):

Android第6讲——Activity的生命周期

当再次返回到主界面时,Logcat中的日志为(红框中为新增的日志):

Android第6讲——Activity的生命周期

点击“显示小活动”按钮后,界面变为:

Android第6讲——Activity的生命周期

此时Logcat中的日志为(红框中为新增的日志):

Android第6讲——Activity的生命周期

当再次返回到主界面时,Logcat中的日志为(红框中为新增的日志):

Android第6讲——Activity的生命周期

退出程序时,Logcat中的日志为(红框中为新增的日志):

Android第6讲——Activity的生命周期

9、后记

这里我们使用了自建的SmallActivity来完成遮挡部分MainActivity界面的功能,AlertDialog也是一个小小的对话框,假如我们将SmallActivity换成AlertDialog怎么样呢?

答案是不会产生部分遮挡时的程序运行逻辑,因为AlertDialog不会入MainActivity所在的栈,有兴趣的朋友可以自己试一下,这里就不提供试验的源代码了。