1.0 新建一個(gè)項(xiàng)目ActivityLifeCycleTest篷角。
新建兩個(gè)活動(dòng)NormalActivity和DialogActivity竖螃,勾選“Generate Layout File”拉鹃。
文件目錄如下:
2.0 修改主活動(dòng)布局,增加兩個(gè)按鈕控件树肃,以響應(yīng)新建好的這兩個(gè)活動(dòng)丐吓,activity_main.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">
<Button
android:id="@+id/start_narmal_activity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="開始NormalActivity活動(dòng)"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="40dp" />
<Button
android:id="@+id/start_dialog_activity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="84dp"
android:text="開始DialogActivity活動(dòng)"
app:layout_constraintTop_toTopOf="@id/start_narmal_activity"
tools:layout_editor_absoluteX="0dp" />
</android.support.constraint.ConstraintLayout>
3.0 在兩個(gè)活動(dòng)布局文件中添加文字打印說(shuō)明,activity_normal.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=".NormalActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="這是一個(gè)普通活動(dòng)"/>
</android.support.constraint.ConstraintLayout>
activity_dialog.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=".DialogActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="這是一個(gè)對(duì)話框式活動(dòng)"/>
</android.support.constraint.ConstraintLayout>
4.0 這里需要修改一下AndroidMainifest.xml中關(guān)于活動(dòng)DialogActivity的內(nèi)容柿汛,以把它變成對(duì)話框式的活動(dòng)主題:
<!--android:theme是給當(dāng)前活動(dòng)指定主題的冗酿,-->
<!--android內(nèi)置了很多主題可以選擇,-->
<!--當(dāng)然我們也可以定制自己的主題-->
<!--當(dāng)前Dialog主題主要就是使用對(duì)話框式的主題-->
<activity
android:name=".DialogActivity"
android:theme="@style/Theme.AppCompat.Dialog"></activity>
<activity android:name=".NormalActivity" />
5.0 最后的大頭,主活動(dòng)MainActivity.java裁替,通過(guò)重寫6個(gè)回調(diào)方法(onCreate()方法在活動(dòng)創(chuàng)建時(shí)自動(dòng)重寫了项玛,而且也必須重寫),通過(guò)logcat調(diào)試監(jiān)控窗口來(lái)體現(xiàn)方法的調(diào)用:
package com.example.activitylifecycletest;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
public static final String TAG = "主活動(dòng)";
@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_narmal_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 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 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");
}
}
6.0 好了弱判,運(yùn)行襟沮,體驗(yàn)一下:
6.1運(yùn)行程序run,進(jìn)入活動(dòng)MainActivity頁(yè)面昌腰,這時(shí)logcat已經(jīng)在打印東西了开伏,調(diào)到Verbose級(jí)別的bug監(jiān)測(cè)(以下監(jiān)測(cè)內(nèi)容都是這個(gè)級(jí)別):
可以看到:
- 一開始時(shí) onCreate() 打印,活動(dòng)一創(chuàng)建自動(dòng)有遭商,每個(gè)活動(dòng)都會(huì)重寫這個(gè)方法硅则。
- 活動(dòng)MainActivity目前處于可見狀態(tài),入棧:
- 此時(shí)調(diào)用onStart() 該方法在活動(dòng)由不可見變?yōu)榭梢姇r(shí)調(diào)用株婴。
- 接著調(diào)用onResume() 該方法在活動(dòng)準(zhǔn)備好和用戶進(jìn)行交互的時(shí)候調(diào)用怎虫,而且活MainActivity的確位于返回棧的棧頂,并處于運(yùn)行狀態(tài)困介。
此時(shí)進(jìn)入如下界面:
6.2 然后大审,點(diǎn)擊第一個(gè)按鈕“開始NORMALACTIVITY活動(dòng)”:
此時(shí)logcat刷新為:
可以看到:
- 此時(shí)活動(dòng)MainActivity將處于不可見狀態(tài),而活動(dòng)NormalActivity將處于可見狀態(tài)座哩,并加入棧頂;于是onPause() 該方法在系統(tǒng)準(zhǔn)備去啟動(dòng)或者恢復(fù)另一個(gè)活動(dòng)的時(shí)候調(diào)用徒扶。活動(dòng)NormalActivity此時(shí)進(jìn)入可見狀態(tài)根穷。
- 接著調(diào)用onStop()方法姜骡,在活動(dòng)MainActivity完全不可見的時(shí)候調(diào)用,它和onPause() 方法的主要區(qū)別是屿良,如果啟動(dòng)的新活動(dòng)是一個(gè)對(duì)話框式的活動(dòng)圈澈,那么onPause() 方法會(huì)得到執(zhí)行,而onStop()方法并不會(huì)執(zhí)行尘惧。
6.3 這時(shí)已經(jīng)進(jìn)入NormalActivity活動(dòng)界面康栈,點(diǎn)擊Back鍵:
此時(shí)logcat刷新為:
可以看到:
- 此時(shí)活動(dòng)NormalActivity將被銷毀,出棧喷橙,而活動(dòng)MainActivity將變?yōu)闂m斏睹矗刹豢梢娮優(yōu)榭梢姞顟B(tài),可見先調(diào)用onRestart()方法先激活活動(dòng)MainActivity贰逾,再調(diào)用onStart()方法悬荣,在活動(dòng)由不可見變?yōu)榭梢姇r(shí)調(diào)用,進(jìn)入可見生存期疙剑,最后調(diào)用onResume()方法氯迂,活動(dòng)MainActivity做好準(zhǔn)備践叠,和用戶進(jìn)行交互,進(jìn)入前臺(tái)生存期囚戚,也在可見生存期內(nèi)。
- 但是我們可以看到轧简,并沒(méi)有調(diào)用 onDestroy()方法去銷毀活動(dòng)驰坊,雖然此時(shí)活動(dòng)NormalActivity已經(jīng)出棧。
7.0 這時(shí)已經(jīng)進(jìn)入MainActivity主活動(dòng)界面哮独,點(diǎn)擊第二個(gè)按鈕“開始DIALOGACTIVITY活動(dòng)”:
此時(shí)logcat刷新為:
可以看到:
- 僅調(diào)用 onPause()方法拳芙,使系統(tǒng)去啟動(dòng)活動(dòng)MialogActivity。因?yàn)閱?dòng)的是一個(gè)對(duì)話框式活動(dòng)皮璧,活動(dòng)MainActivity并不會(huì)被執(zhí)行onStop()方法舟扎。
- 除此之外,并沒(méi)有執(zhí)行其他回調(diào)函數(shù)悴务,說(shuō)明活動(dòng)MainActivity退出前臺(tái)生存期睹限,但是處于可見生存期內(nèi)。
8.0 這時(shí)進(jìn)入如下畫面:
如上圖箭頭讯檐,點(diǎn)擊Back鍵:
此時(shí)logcat刷新為:
可以看到:
- 對(duì)話框式活動(dòng)直接返回上一活動(dòng)羡疗,并不需要執(zhí)行onStop()方法,因?yàn)榛顒?dòng)MainActivity并不處于完全不可見狀態(tài)别洪。直接返回調(diào)用onResume()方法叨恨。
- onResume()方法在活動(dòng)MainActivity準(zhǔn)備好和用戶進(jìn)行交互的時(shí)候調(diào)用。
9.0 這時(shí)進(jìn)入如下界面:
10.0 點(diǎn)擊Back鍵:
此時(shí)logcat刷新為:
可以看到:
- 程序立馬執(zhí)行onPause()方法挖垛,釋放CPU資源痒钝,保存關(guān)鍵數(shù)據(jù),前臺(tái)生存期結(jié)束痢毒。
- 活動(dòng)MainActivity進(jìn)入完全不可見狀態(tài)送矩,所以調(diào)用onStop()方法,可見生存期結(jié)束哪替。
- 最后整個(gè)活動(dòng)被銷毀益愈,調(diào)用onDestroy,一個(gè)完成生存期結(jié)束夷家。
- 可見onDestroy()方法調(diào)用蒸其,會(huì)在整個(gè)app應(yīng)用程序退出時(shí)調(diào)用。
11.0 最后退出軟件:
12.0 再結(jié)合官方的活動(dòng)生命示意圖库快,一下就理解了:
13.0 還有一個(gè)問(wèn)題:當(dāng)用戶在活動(dòng)A的基礎(chǔ)上啟動(dòng)了活動(dòng)B摸袁,這個(gè)時(shí)候由于內(nèi)存不足,活動(dòng)A被回收义屏,這時(shí)候當(dāng)從活動(dòng)B返回時(shí)靠汁,活動(dòng)A將重新創(chuàng)建蜂大,并丟失待機(jī)時(shí)可能存在的數(shù)據(jù),這樣嚴(yán)重影響用戶體驗(yàn)的蝶怔。
onSaveInstanceState()回調(diào)方法可以解決活動(dòng)被回收時(shí)臨時(shí)數(shù)據(jù)得不到保存的問(wèn)題奶浦。
這個(gè)方法能夠保證在活動(dòng)被收回之前一定會(huì)被調(diào)用。
在MainActivity.java中添加如下代碼就可以實(shí)現(xiàn):
// 該方法攜帶一個(gè)Bundle類型的參數(shù)踢星,該參數(shù)提供一系列方法用于保存數(shù)據(jù)
// 可以使用putString()方法保存字符串
// 使用putInt()方法保存整型數(shù)據(jù)
@Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState);
String tempData = "你剛剛編輯的臨時(shí)東西";
// 使用putString()方法保存字符串
// 需要提供兩個(gè)參數(shù)澳叉,一個(gè)是鍵名,第二個(gè)才是需要保存的內(nèi)容
outState.putString("data_key",tempData);
}
數(shù)據(jù)保存下來(lái)沐悦,恢復(fù)怎么辦成洗?
其實(shí)我們一直使用的onCreate()方法,自帶有一個(gè)Bundle類型的參數(shù)藏否,這個(gè)參數(shù)一般情況是null瓶殃,所以只要我們通過(guò)onSaveInstanceState()方法保存數(shù)據(jù),這個(gè)參數(shù)就會(huì)帶著之前保存的全部數(shù)據(jù)副签。
我們只需要取出來(lái)即可遥椿,修改MainActivity方法的onCreate()方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG,"onCreate");
setContentView(R.layout.activity_main);
if (savedInstanceState != nule){
String tempData = savedInstanceState.getString("data_key");
Log.d(TAG,tempData);
}
......
}