Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android之Activity生命周期的淺析(二)

Android之Activity生命周期的淺析(二)

編輯:關於Android編程

??上一篇文章,我們主要分析了Activity的正常情況下生命周期及其方法,本篇主要涉及內容為Activity的異常情況下的生命周期。

Activity異常生命周期

??異常的生命周期是指Activity被系統回收或者當前設備的Configuration發生變化(一般指橫豎屏切換)從而導致Activity被銷毀重建。異常的生命周期主要分以下兩種情況:

1、相關的系統配置發生改變導致Activity被殺死並重新創建(一般指橫豎屏切換)

2、內存不足導致低優先級的Activity被殺死

1、相關的系統配置發生改變導致Activity被殺死並重新創建(一般指橫豎屏切換)

我們先來分析第一種情況,當Activity處於豎屏狀態,如果突然旋轉屏幕,由於系統配置發生了變化,在默認的情況下,Activity會被銷毀並重新創建,當然我們可以人為干預來防止這種情況。在這裡首先我們使用上一篇文章的測試代碼來驗證此過程,代碼如下:

package com.cmcm.activitylifecycle;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    Button bt;

    /**
     * Activity創建時被調用
     * @param savedInstanceState
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LogUtils.e("onCreate is invoke!!!");
        bt= (Button) findViewById(R.id.bt);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(i);
            }
        });
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        LogUtils.e("onSaveInstanceState is invoke!!!");
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        LogUtils.e("onRestoreInstanceState is invoke!!!");
    }

    /**
     * Activity從後台重新回到前台時被調用
     */
    @Override
    protected void onRestart() {
        super.onRestart();
        LogUtils.e("onRestart is invoke!!!");
    }

    /**
     *Activity創建或者從後台重新回到前台時被調用
     */
    @Override
    protected void onStart() {
        super.onStart();
        LogUtils.e("onStart is invoke!!!");
    }


    /**
     *Activity創建或者從被覆蓋、後台重新回到前台時被調用
     */
    @Override
    protected void onResume() {
        super.onResume();
        LogUtils.e("onResume is invoke!!!");
    }

    /**
     *  Activity被覆蓋到下面或者鎖屏時被調用
      */
    @Override
    protected void onPause() {
        super.onPause();
        LogUtils.e("onPause is invoke!!!");
    }

    /**
     *退出當前Activity或者跳轉到新Activity時被調用
     */
    @Override
    protected void onStop() {
        super.onStop();
        LogUtils.e("onStop is invoke!!!");
    }

    /**
     *退出當前Activity時被調用,調用之後Activity就結束了
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        LogUtils.e("onDestroy is invoke!!!");
    }
}

??代碼比較簡單,我們重寫了onSaveInstanceState方法和onRestoreInstanceState方法,這兩個方法後面我們會詳細介紹,這裡先看看運行結果:
Snip20160716_8
??從Log中我們可以看出當我們正常啟動Activity時,onCreate,onStart,onResume方法都會依次被回調,而如果我們此時把豎屏的Activity人為的調整為橫屏,我們可以發現onPause,onSaveInstanceState,onStop,onDestroy,onCreate,onStart,onRestoreInstanceState,onResume依次被調用,單從調用的方法我們就可以知道,Activity先被銷毀後再重新創建,其異常生命周期如下:
Snip20160716_9
??現在異常生命周期的流程我們大概也就都明白,但是onSaveInstanceState和onRestoreInstanceState方法是干什麼用的呢?實際上這兩個方法是系統自動調用的,當系統配置發生變化後,Activity會被銷毀,也就是onPause,onStop,onDestroy會被依次調用,同時因為Activity是在異常情況下銷毀的,android系統會自動調用onSaveInstanceState方法來保存當前Activity的狀態信息,因此我們可以在onSaveInstanceState方法中存儲一些數據以便Activity重建之後可以恢復這些數據,當然這個方法的調用時機必須在onStop方法之前,也就是Activity停止之前。至跟onPause方法的調用時機可以隨意。而通過前面的Log信息我們也可以知道當Activity被重新創建之後,系統還會去調用onRestoreInstanceState方法,並把Activity銷毀時通過onSaveInstanceState方法保存的Bundle對象作為參數同時傳遞給onRestZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcmVJbnN0YW5jZVN0YXRlus1vbkNyZWF0Zbe9t6ijrNLytMvO0sPHv8nS1M2ouf1vblJlc3RvcmVJbnN0YW5jZVN0YXRlus1vbkNyZWF0Zbe9t6jAtMXQts9BY3Rpdml0ecrHt/Gxu9bY0MK0tL2oo6zMyMj0sbvW2L2owcujrM7Sw8e+zb/J0tS21Naux7C1xMr9vt29+NDQu9a4tKGjtNNMb2fQxc+io6zO0sPHv8nS1L+0s/ZvblJlc3RvcmVJbnN0YW5jZVN0YXRlt723qLXEtffTw8qxu/rKx9Tab25TdGFydNauuvO1xKGjPHN0cm9uZz7V4sDv09C149Do0qrM2LHw16LS4qOsb25TYXZlSW5zdGFuY2VTdGF0ZbrNb25SZXN0b3JlSW5zdGFuY2VTdGF0Zda709DU2kFjdGl2aXR50uyzo9bV1rnKsbLFu+Gxu7X308O1xKOs1f2zo8fpv/bKx7K7u+G199PD1eLBvbj2t723qLXEoaM8L3N0cm9uZz48YnIgLz4NCj8/tb3V4sDvtPO80r/JxNy7udPQ0ru49tLJzsqjrG9uUmVzdG9yZUluc3RhbmNlU3RhdGW6zW9uQ3JlYXRlt723qLa8v8nS1L340NDK/b7du9a4tKOsxMe1vbXX08PExLj2sKE/xuTKtcG91d+2vL/J0tSjrMG91d+1xMf4sfDU2tPao6xvblJlc3RvcmVJbnN0YW5jZVN0YXRlt723qNK7tamxu8+1zbO72LX3o6zG5LLOyv1CdW5kbGXSu7aosrvOqr/Vo6zO3tDotu7N4rXExdC2z6OstvhvbkNyZWF0ZbXEQnVuZGxlyLSyu9K7tqjT0Na1o6zS8s6qyOe5+0FjdGl2aXR5ysfV/bOjxvS2r7XEu7CjrEJ1bmRsZbLOyv3Kx7K7u+HT0Na1tcSjrNLytMvO0sPH0OjSqrbuzeK1xMXQts/M9bz+o6y1sci7y+TLtcG91d+2vL/J0tTK/b7du9a4tKOstau4/Mfjz/LT2m9uUmVzdG9yZUluc3RhbmNlU3RhdGW3vbeooaM8YnIgLz4NCj8/1+6687u509C1487Sw8fSqtaqtcC1xMrHo6zU2m9uU2F2ZUluc3RhbmNlU3RhdGW3vbeous1vblJlc3RvcmVJbnN0YW5jZVN0YXRlt723qNbQo6xhbmRyb2lkz7XNs7vh19S2r7DvztLDx7vWuLTSu7aotcTK/b7do6zI57Wxx7BBY3Rpdml0ebXEytPNvL3hubmjrM7Esb6/8rXEyv2+3aOsTGlzdFZpZXe1xLn2tq/Ou9bDtcijrNXi0KlWaWV3z+C52LXE17TMrM+1zbO2vLvhsO/O0sPHu9a4tKOs1eLKx9LyzqrDv7j2Vmlld9Ky09BvblNhdmVJbnN0YW5jZVN0YXRlt723qLrNb25SZXN0b3JlSW5zdGFuY2VTdGF0Zbe9t6ijrM7Sw8fAtLLiytTSu7j2wP3X06Os1NpFZGl0VGV4dM7Esb6/8tbQyuTI68r9vt3Iu7rzx9C7u7rhyvrGwcS7o6y94bn7yOfPwqO6PGJyIC8+DQo8aW1nIGFsdD0="Snip20160716_11" src="/uploadfile/Collfiles/20160718/201607181017471474.png" title="\" />Snip20160716_10
由此可以知道,系統確實幫我們恢復了Activity結構和View的相關數據。

2、內存不足導致低優先級的Activity被殺死

??接下來我們來聊聊內存不足導致低優先級的Activity被殺死,然後重建,其實也不用聊了,其數據的存儲過程和恢復過程跟上面的情況基本沒差。我們還是繼續聊聊Activity被殺死的情況吧,當系統內存不足的時候,系統就會按照一定的優先級去殺死目標Acitivity的進程來回收內存,並且此時Activity的onSaveInstanceState方法會被調用來存儲數據,並在後續Activity恢復時調用onRestoreInstanceState方法來恢復數據,所以為了Activity所在進程盡量不被殺死,我們應該盡量讓其保持高的優先級。那什麼樣的優先級較高呢?為了更深入了解這個問題,我們先來進入一個新的話題,Android 進程層次。

Android 進程層次

??在android系統中最重要的進程被稱為前台進程,然後依次是任何可見進程、服務進程、後台進程,最後是空進程。接下來我們將進一步展開。
??在開始之前我們先要明確一個問題,當我們談論進程優先級的時候是以 activity、service 這樣的組件來說的,但請注意這些優先級是在進程的級別上的,而非組件級別。只要有一個組件是前台進程,就會將整個進程變為前台進程。同時我們要知道絕大多數應用是單進程的,如果我們有生命周期差異很大的不同部分或者某個部分非常重量型,那麼我們強烈建議把它們分為不同的進程,以便讓重量級進程盡早被系統回收。
明白這點後我們再看看下面一張圖(圖來自Who lives and who dies? Process priorities on Android):
android_process
從圖中我們可以看出共有5中優先級線程,Foreground Processes ,Visible Processes ,Service Processes , Background Processes , Empty Processes ;

1.Foreground Processes(前台進程)

??系統中前台進程的數量很少(這點從圖中也是可以看出來的), 前台進程幾乎不會被殺死. 只有當內存低到無法保證所有的前台進程同時運行時才會選擇殺死某個前台進程.以下幾種都屬於前台進程:
a. 處於前台正與用戶交互的activity
b. 與前台activity綁定的service
c. 調用了startForeground()方法的service
d. 正在執行onCreate(), onStart(), 或onDestroy()方法的service
e. 正在執行onReceive()方法的BroadcastReceiver.
凡是包含以上任意一種情況的進程都是前台進程。當然一些 activity 在依靠他們成為前台進程的同事,也可能依賴 bound service 。任何進程,如果它持有一個綁定到前台 activity 的服務,那麼它也被賦予了同樣的前台優先級。

2.Visible Processes(可視進程)

??此時如果一個Activity可見但並非處於前台時,如在Activity中彈出了一個對話框,從而導致Activity可見但位於後台無法與用戶交互,這個進程就可以被視為可見進程,同時我們也必須明白可見 activity 的 bound service 和 content provider 也處於可見進程狀態。這同樣是為了保證使用中的 activity 所依賴的進程不會被過早地殺掉。但還是需要注意的是,只是可見並不意味著不能被殺掉。如果來自前台進程的內存壓力過大,可見進程仍有可能被殺掉。從用戶的角度看,這意味著當前 activity 背後的可見 activity 會被黑屏代替。當然,倘若我們正確地重建 activity ,在前台 activity 關閉之後,我們的進程和 activity 會立刻恢復而沒有數據損失。

3.Service Processes(服務進程)

??如果我們通過startService()啟動一個service服務,那麼它被看作是一個服務進程。對於許多在後台做處理(如異步加載數據,獲取耗時資源等)而沒有立即成為前台服務的app都屬於這種情況。這是比較常見也是最合理的後台處理方式,這種進程只有在可見進程和前台進程內存不足時才有可能被殺掉。

4.Background Processes(後台進程)

??假如我們的Activity目前是前台進程,但是這時候,我們點Home鍵,將導致onPause,onStop方法被調用,我們的進程也就變成了後台進程,當然我們的後台進程並不會被立馬殺死,所以這些進程會保留一段時間,直到更高優先級進程需要內存的時候才被回收,並且是按照最近最少使用順序(最少使用的會被優先回收)。很多時候我們會發現手機的內存大都是被後台App進程占用了大部分空間,而android系統這樣做的好處是可以使用我們在下次重新打開此進程的app時無需重新分配和加載資源,從而擁有更好的用戶體驗。
。然而內存不足的時候,他們仍然會被殺掉,所以我們應該和可見 activity 處理情況一樣,應該盡量能夠在不丟失用戶狀態的情況下重建這些 activity ,以便達到更佳的用戶體驗。

5.Empty Processes(空進程)

??在任何層次中,空進程都是最低優先級的。如果我們的進程不屬於以上類別,那它就是空進程。空進程是沒有活躍的組件,只是出於緩存的目的而被保留(為了更加有效地使用內存而不是完全釋放掉),只要 Android 系統內存需要可以隨時殺掉它們。

嗯,現在我們應該對android進程有個比較明確的概念了,回到之前的的Activity內存不足被android系統殺死的話題,為了防止一些重要的Activity不被意外殺死,我們應該讓當前所在進程的Activity保持較高的優先級,如使其變為前台進程,或者通過service去綁定,也可以讓其成為單獨的進程。當然如果真的不幸被殺死,我們也應該盡量通過onSaveInstanceState方法和onRestoreInstanceState方法來保存和恢復數據,以便獲得更佳的用戶體驗。

解決Activity銷毀重建問題

通過上面的分析我們知道當系統配置發生變化後,Activity會被重建,那有沒有辦法使其不重建呢?方法自然是有的,那就是我們可以給Activity指定configChange屬性,當我們不想Activity在屏幕旋轉後導致銷毀重建時,可以設置configChange=“orientation”;當SDK版本大於13時,我們還需額外添加一個“screenSize”的值,對於這兩個值含義如下:
orientation:屏幕方向發生變化,配置該參數可以解決橫豎屏切換時,Activity重建問題(API<13)
screenSize:當設備旋轉時,屏幕尺寸發生變化,API>13後必須配置該參數才可以保證橫豎切換不會導致Activity重建。
說白了就是設置了這兩個參數後,當橫豎屏切換時,Activity不會再重建並且也不會調用之前相關的方法,取而代之的是回調onConfigurationChanged方法。案例代碼如下:



    
        
            
                

                
            
        

        
    

在MainActivity中我們重寫onConfigurationChanged,原型如下:

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        LogUtils.e("onConfigurationChanged is invoke!!!");
    }

我們運行程序,然後執行橫豎屏切換,看看打印的Log信息:
\
從Log可以看到Activity確實沒有重建,並且也沒有回調onSaveIntanceState方法和RestoreInstanceState方法來存儲或者恢復數據,相反的是onConfigurationChanged方法被回調了,因此我們在這種情況下,可以在此方法中做一些額外的工作。

好了,到此也就結束本篇內容。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved