Activity基礎(chǔ)


指定首次啟動的Activity

必須在manifest使用包括 MAIN action 與 LAUNCHER category 的<intent-filter>標(biāo)簽來聲明。

<activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

如果程序中沒有聲明了MAIN action 或者LAUNCHER category的activity,那么在設(shè)備的主界面列表里面不會呈現(xiàn)app圖標(biāo)。

生命周期

image.png

onCreate

在onCreate()方法中定義UI以及實例化類成員變量。
onCreate里面盡量少做事情,避免程序啟動太久都看不到界面
一旦onCreate 操作完成,系統(tǒng)會迅速調(diào)用onStart() 與onResume()方法。我們的activity不會在Created或者Started狀態(tài)停留。技術(shù)上來說, activity在onStart()被調(diào)用后開始被用戶可見,但是 onResume()會迅速被執(zhí)行使得activity停留在Resumed狀態(tài),直到一些因素發(fā)生變化才會改變這個狀態(tài)。

onDestory

大多數(shù) app并不需要實現(xiàn)這個方法,因為局部類的references會隨著activity的銷毀而銷毀,并且我們的activity應(yīng)該在onPause()與onStop()中執(zhí)行清除activity資源的操作。然而,如果activity含有在onCreate調(diào)用時創(chuàng)建的后臺線程,或者是其他有可能導(dǎo)致內(nèi)存泄漏的資源,則應(yīng)該在OnDestroy()時進(jìn)行資源清理,殺死后臺線程。

onStart

當(dāng)activity從Stopped狀態(tài)回到前臺時,它會調(diào)用onRestart().系統(tǒng)再調(diào)用onStart()方法,onStart()方法會在每次activity可見時都會被調(diào)用。onRestart()方法則是只在activity從stopped狀態(tài)恢復(fù)時才會被調(diào)用,因此我們可以使用它來執(zhí)行一些特殊的恢復(fù)(restoration)工作,請注意之前是被stopped而不是destrory。

為onStop()方法應(yīng)該做清除所有activity資源的操作,我們需要在重啟activtiy時重新實例化那些被清除的資源,同樣, 我們也需要在activity第一次創(chuàng)建時實例化那些資源。介于上面的原因,應(yīng)該使用onStart()作為onStop()所對應(yīng)方法。因為系統(tǒng)會在創(chuàng)建activity與從停止?fàn)顟B(tài)重啟activity時都會調(diào)用onStart()。

也就是說,我們在onStop里面做了哪些清除的操作,就該在onStart里面重新把那些清除掉的資源重新創(chuàng)建出來。因為用戶很可能在回到這個activity之前已經(jīng)過了很長一段時間,所以onStart()方法是一個比較好的地方來驗證某些必須的系統(tǒng)特性是否可用

onResume

系統(tǒng)每次調(diào)用這個方法時,activity都處于前臺,包括第一次創(chuàng)建的時候。所以,應(yīng)該實現(xiàn)onResume()來初始化那些在onPause方法里面釋放掉的組件,并執(zhí)行那些activity每次進(jìn)入Resumed state都需要的初始化動作 (例如開始動畫與初始化那些只有在獲取用戶焦點時才需要的組件)

onPause

通常應(yīng)該在onPause()回調(diào)方法里面做以下事情:

  • 停止動畫或者是其他正在運行的操作,那些都會導(dǎo)致CPU的浪費.
  • 提交在用戶離開時期待保存的內(nèi)容(例如郵件草稿).
  • 釋放系統(tǒng)資源,例如broadcast receivers, sensors (比如GPS), 或者是其他任何會影響到電量的資源。

通常,不應(yīng)該使用onPause()來保存用戶改變的數(shù)據(jù) (例如填入表格中的個人信息) 到永久存儲(File或者DB)上。僅僅當(dāng)確認(rèn)用戶期待那些改變能夠被自動保存的時候(例如正在撰寫郵件草稿),才把那些數(shù)據(jù)存到永久存儲 。但是,我們應(yīng)該避免在onPause()時執(zhí)行CPU-intensive 的工作,例如寫數(shù)據(jù)到DB,因為它會導(dǎo)致切換到下一個activity變得緩慢(應(yīng)該把那些heavy-load的工作放到onStop()去做)。

當(dāng)activity處于暫停狀態(tài),Activity實例是駐留在內(nèi)存中的,并且在activity 恢復(fù)的時候重新調(diào)用。我們不需要在恢復(fù)到Resumed狀態(tài)的一系列回調(diào)方法中重新初始化組件。

onStop

當(dāng)activity調(diào)用onStop()方法, activity不再可見,并且應(yīng)該釋放那些不再需要的所有資源。一旦activity停止了,系統(tǒng)會在需要內(nèi)存空間時摧毀它的實例(和棧結(jié)構(gòu)有關(guān),通常back操作會導(dǎo)致前一個activity被銷毀)。極端情況下,系統(tǒng)會直接殺死我們的app進(jìn)程,并不執(zhí)行activity的onDestroy()回調(diào)方法, 因此我們需要使用onStop()來釋放資源,從而避免內(nèi)存泄漏。

activity已經(jīng)停止后,Activity對象會保存在內(nèi)存中,并在activity resume時被重新調(diào)用。我們不需要在恢復(fù)到Resumed state狀態(tài)前重新初始化那些被保存在內(nèi)存中的組件。系統(tǒng)同樣保存了每一個在布局中的視圖的當(dāng)前狀態(tài),如果用戶在EditText組件中輸入了text,它會被保存,因此不需要保存與恢復(fù)它。

釋放資源

onDestory

是我們最后去清除那些可能導(dǎo)致內(nèi)存泄漏的地方。因此需要確保那些線程都被destroyed并且所有的操作都被停止。

onSaveInstanceState()

Activity被銷毀的情況:

  • Activity是由于正常的程序行為而被Destory的
  • 系統(tǒng)也有可能會在Activity處于stop狀態(tài)且長時間不被使用,或者是在前臺activity需要更多系統(tǒng)資源的時關(guān)閉后臺進(jìn)程,以圖獲取更多的內(nèi)存。

正常情況下銷毀activity系統(tǒng)就丟失了對Activity實例的引用,因為這一行為意味著不再需要這個activity了。然而,如果因為系統(tǒng)資源緊張而導(dǎo)致Activity的Destory, 系統(tǒng)會在用戶回到這個Activity時有這個Activity存在過的記錄,系統(tǒng)會使用那些保存的記錄數(shù)據(jù)(描述了當(dāng)Activity被Destory時的狀態(tài))來重新創(chuàng)建一個新的Activity實例。那些被系統(tǒng)用來恢復(fù)之前狀態(tài)而保存的數(shù)據(jù)被叫做 "instance state" ,它是一些存放在Bundle對象中的key-value pairs

默認(rèn)情況下, 系統(tǒng)使用 Bundle 實例來保存每一個View(視圖)對象中的信息(例如輸入EditText 中的文本內(nèi)容)。因此,如果Activity被destroyed與recreated, 則layout的狀態(tài)信息會自動恢復(fù)到之前的狀態(tài)。然而,activity也許存在更多你想要恢復(fù)的狀態(tài)信息。

為了使Android系統(tǒng)能夠恢復(fù)Activity中的View的狀態(tài),每個View都必須有一個唯一ID,由android:id定義。

為了可以保存額外更多的數(shù)據(jù)到saved instance state。在Activity的生命周期里面存在一個額外的回調(diào)函數(shù),你必須重寫這個函數(shù)。該回調(diào)函數(shù)并沒有在前面課程的圖片示例中顯示。這個方法是onSaveInstanceState() ,當(dāng)用戶離開Activity時,系統(tǒng)會調(diào)用它。當(dāng)系統(tǒng)調(diào)用這個函數(shù)時,系統(tǒng)會在Activity被異常Destory時傳遞 Bundle 對象,這樣我們就可以增加額外的信息到Bundle中并保存到系統(tǒng)中。若系統(tǒng)在Activity被Destory之后想重新創(chuàng)建這個Activity實例時,之前的Bundle對象會(系統(tǒng))被傳遞到你我們activity的onRestoreInstanceState()方法與 onCreate() 方法中。

onRestoreInstanceState

當(dāng)activity重新初始化時,這個方法在onstart()之后調(diào)用,他可以取出onSaveInstanceState()中存儲的數(shù)據(jù)

onCreate中也可以取出instance state ,但是,在完成所有初始化之后,或者允許子類決定是否使用默認(rèn)實現(xiàn),在這里做這項工作有時是很方便的

image.png

TEST

創(chuàng)建一個新的activity,然后在我們上面說道的生命周期中都打日志,觀察他們執(zhí)行的流程

private static final String TAG = "MainActivity";

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

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

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

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.e(TAG, "onRestoreInstanceState: ");
    }

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

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

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.e(TAG, "onSaveInstanceState: ");
    }

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

  • 打開該activity:
07-17 14:49:48.628 18505-18505/com.example.frc.trainingapp E/MainActivity: onCreate: 
07-17 14:49:48.648 18505-18505/com.example.frc.trainingapp E/MainActivity: onStart: 
07-17 14:49:48.648 18505-18505/com.example.frc.trainingapp E/MainActivity: onResume:
  • 按home鍵退到后臺
07-17 14:50:18.518 18505-18505/com.example.frc.trainingapp E/MainActivity: onPause: 
07-17 14:50:18.568 18505-18505/com.example.frc.trainingapp E/MainActivity: onSaveInstanceState: 
07-17 14:50:18.568 18505-18505/com.example.frc.trainingapp E/MainActivity: onStop: 
  • 回到前臺:
07-17 14:57:27.788 18505-18505/com.example.frc.trainingapp E/MainActivity: onRestart: 
07-17 14:57:27.788 18505-18505/com.example.frc.trainingapp E/MainActivity: onStart: 
07-17 14:57:27.788 18505-18505/com.example.frc.trainingapp E/MainActivity: onResume: 

-跳轉(zhuǎn)到下個SecondActivity頁面

07-17 15:01:44.238 30168-30168/com.example.frc.trainingapp E/MainActivity: onPause: 
07-17 15:01:44.268 30168-30168/com.example.frc.trainingapp E/SecondActivity: onCreate: 
07-17 15:01:44.268 30168-30168/com.example.frc.trainingapp E/SecondActivity: onStart: 
07-17 15:01:44.268 30168-30168/com.example.frc.trainingapp E/SecondActivity: onResume: 
07-17 15:01:44.758 30168-30168/com.example.frc.trainingapp E/MainActivity: onSaveInstanceState: 
07-17 15:01:44.758 30168-30168/com.example.frc.trainingapp E/MainActivity: onStop:

發(fā)現(xiàn)當(dāng)?shù)诙€頁面顯示后(onResume)第一個頁面才會不可見(onStop)

  • 回到第一個頁面:
07-17 15:03:59.308 30168-30168/com.example.frc.trainingapp E/SecondActivity: onPause: 
07-17 15:03:59.318 30168-30168/com.example.frc.trainingapp E/MainActivity: onRestart: 
07-17 15:03:59.318 30168-30168/com.example.frc.trainingapp E/MainActivity: onStart: 
07-17 15:03:59.318 30168-30168/com.example.frc.trainingapp E/MainActivity: onResume: 
07-17 15:03:59.788 30168-30168/com.example.frc.trainingapp E/SecondActivity: onStop: 
07-17 15:03:59.788 30168-30168/com.example.frc.trainingapp E/SecondActivity: onDestroy: 
  • 將手機橫盤(不要禁止橫豎屏幕切換)
07-17 15:07:27.088 30168-30168/com.example.frc.trainingapp E/MainActivity: onPause: 
07-17 15:07:27.088 30168-30168/com.example.frc.trainingapp E/MainActivity: onSaveInstanceState: 
07-17 15:07:27.088 30168-30168/com.example.frc.trainingapp E/MainActivity: onStop: 
07-17 15:07:27.088 30168-30168/com.example.frc.trainingapp E/MainActivity: onDestroy: 
07-17 15:07:27.108 30168-30168/com.example.frc.trainingapp E/MainActivity: onCreate: 
07-17 15:07:27.128 30168-30168/com.example.frc.trainingapp E/MainActivity: onStart: 
07-17 15:07:27.138 30168-30168/com.example.frc.trainingapp E/MainActivity: onRestoreInstanceState: 
07-17 15:07:27.138 30168-30168/com.example.frc.trainingapp E/MainActivity: onResume: 

通過切換橫豎屏幕模擬activity被異常銷毀

google官網(wǎng)的圖,挺不錯的:

image.png
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容