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所在的棧,有興趣的朋友可以自己試一下,這裏就不提供試驗的源代碼了。