Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android應用常規開發技巧——善用組件生命周期

Android應用常規開發技巧——善用組件生命周期

編輯:關於Android編程

數據管理
對於只讀數據,一種常用的管理模式是在onCreate函數中進行數據的加載,直到組件的onDestory函數被調用時在進行釋放。

    // 緩存只讀的數據
    private Object       readOnlyData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           // 讀取數據到內存
           readOnlyData = readOnlyData();
   }

    private Object readOnlyData() {
           return null ;
   }

    @Override
    protected void onDestroy() {
           super.onDestroy();
           // 將數據置空,加速回收
           readOnlyData = null ;
   }

如果數據支持讀寫操作,則需要在onResume或者onCreate中進行讀取,而在onPause中實現存儲。
因為當onPause函數被調用後,該界面組件就處於可回收的狀態。當資源緊張時,系統會強行銷毀組件對象。
對象中所有未持久化的修改就會丟失。對於讀寫數據處理的模型示例如下:

    // 緩存可讀寫的數據
    private Object       data;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           // 讀取數據到內存
           data = readData();
   }

    @Override
    protected void onResume() {
           super.onResume();
           data = readData();
   }

    private Object readData() {
           // TODO 讀取數據
           return null ;
   }

    private void writeData(Object data) {
           // TODO 寫入數據
   }

    @Override
    protected void onPause() {
           super.onPause();
          writeData( data);
   }

    @Override
    protected void onDestroy() {
           super.onDestroy();
           // 將數據置空,加速回收
           data = null ;
   }

狀態管理

當系統將界面組件切離前台狀態(即onPause函數調用前),會先行調用onSavaInstanceState函數。在該函數中,開發者可以講組件中的狀態數據寫入參數的outState對象中。outState的對象類型是Bundle,他是通過鍵值對的方式進行數據的存儲。

onCreate —— 如果含有state數據,則先調用onRestoreInstanceState。
onRestoreInstanceState —— 組件進入前台狀態前,先調用恢復數據。
onSaveInstanceState —— 組件離開前台狀態,先調用狀態保存數據,在調用onPause。如果用戶是主動離開前台狀態,則不會觸發該狀態。

    boolean       needSaveDraft = true;

    // 如果是非主動離開時,則會調用onSaveInstanceState
    @Override
    protected void onSaveInstanceState(Bundle outState) {
           super.onSaveInstanceState(outState);
           // 先保存修改狀態,用於恢復啟動時恢復該信息
          outState.putBoolean( NEED_SAVE_DRAFT, needSaveDraft );
           // 表示在被動退出時無需保存
           needSaveDraft = false ;
   }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
           super.onRestoreInstanceState(savedInstanceState);
           if (savedInstanceState != null) {
                  needSaveDraft = savedInstanceState.getBoolean(NEED_SAVE_DRAFT );
          }
   }

    @Override
    protected void onPause() {
           super.onPause();
           // 如果不是被動推動,則詢問用戶
           if (needSaveDraft ) {
                 showAskSaveDraftDialog();
          }
   }

    private void showAskSaveDraftDialog() {
           // TODO Auto-generated method stub

   }

當前onSaveInstanceState函數調用完成後,存儲狀態信息的outState對象中的數據就由系統進程代為保管,不論該應用進程是否被系統回收,這些數據都不會丟失。

如果savedInstanceState為空,說明這是一次全新的構造,反之則說明這是一次恢復性的構造。界面組件可以利用該參數中的信息將界面狀態恢復到系統回收前的狀態。

區分是恢復性構造還是全新的狗仔,是開發中需要妥善處理的細節。如果是全新的構造,界面組件中需要分析調用發送的Intent對象,控制業務流程;而如果是恢復性構造,則需要將上次緩存的信息一一恢復。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           if (savedInstanceState != null) {
                  needSaveDraft = savedInstanceState.getBoolean(NEED_SAVE_DRAFT );
          }
           else {
                  // TODO 解析Intent對象傳入的參數或者Action
                  // Intent intent = getIntent();
                  // intent.getBundleExtra();
          }
   }

為了降低開發者的負擔,Android中的大部分的系統控件都實現了狀態緩存的邏輯。在onSaveInstanceState函數調用前,界面組件會遍歷整個控件樹,將各個控件保存下來。等到onRestoreInstanceState函數被調用時在進行恢復。

如果系統內置的控件狀態緩存邏輯不符合開發者的需求,開發者可以調用View.setSaveEnabled函數關閉對應控件對象的自動緩存,在onSaveInstanceState函數中自行管理控件的狀態。

用於狀態管理的onSaveInstanceState 和 onRestoreInstanceState並不屬於基本的生命周期函數,但是狀態管理的操作還是和組件的生命周期有必然的聯系,開發者同樣需要妥善利用好這些函數,處理由於生命周期變更引起的變化。

注冊管理
界面組件在於用戶交互的過程中有時候需要隨著系統狀態的變化及時的更新信息。比如地址信息。

界面組件可以通過監聽相關的事件信息來捕獲這些變化。如果所監聽的事件的變化,僅當組件在前台狀態時才需要生效(比如廣播事件的監聽,地理位置的變更等),則需要早onResume中注冊,在onPause中注銷。

   LocationManager             mLocationManager;
   LocationListener      mLocationListener;

    @Override
    protected void onResume() {
           super.onResume();
           mLocationManager.requestLocationUpdates(provider, minTime, minDistance, listener );
   }

    @Override
    protected void onPause() {
           super.onPause();
           mLocationManager.removeUpdates(mLocationListener );
   }

線程管理

在應用開發中,網絡通信、數據操作、復雜計算等都需要耗費大量的時間,因此應用通常需要采用多線程的設計模式,在後台線程中執行此類耗時的操作。

Android的組件生命周期,是一個典型的同步處理邏輯。對於多線程架構沒有提供良好的支持模型。這個需要開發者根據自己的需求,充分利用好組件的生命周期,合理的安排線程的構造及銷毀。

如果線程的生命周期和該組件的生命周期緊密聯系,就需要在界面組件生命周期中管理該線程,一旦線程被界面組件構造出來,就需要在onDestory中明確終止該線程,回收其線程空間。否則,將導致線程資源洩漏。
但是僅在onDestory回收線程依然不夠完美,因為在資源緊張的情況下,系統會強行回收組件,此時組件的onDestory函數可能並沒有調用,從而導致線程資源洩漏。

一個更好的線程管理方案,是將線程的句柄信息當做界面組件的狀態信息緩存下來。如果系統強行回收該對象組件,則需要在組件再次被構造時,根據緩存的線程句柄找到該線程,從而避免線程洩露。

static final String THREAD_WORKER_ID = “thread_id”;
Thread workerThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           if (savedInstanceState != null) {
                  long threadId = savedInstanceState.getLong(THREAD_WORKER_ID);
                  workerThread = findThreadById(threadId);
          }
           else {
                  // TODO 創建新的線程
          }
   }

    private Thread findThreadById( long id) {
           // 完善根據線程id,找到該線程 的過程 http://bao231.iteye.com/blog/1917616?utm_source=tuicool 

           return null ;
   }

    @Override
    protected void onDestroy() {
           super.onDestroy();
           if (workerThread != null) {
                  workerThread.interrupt();
                  workerThread = null ;
          }
   }

服務組件的生命周期

服務的使用方式可分為兩種,分別是調用服務和綁定服務。這兩種不同的使用方式下,生命周期略微有不同。
但不論在何種使用模式下,組件的生命周期都是從onCreate中開始,至onDestory中結束。因為服務組件開發中,可以選擇在onCreate中做數據加載等初始化工作,而在onDestory中做數據銷毀,線程終止等清理工作。

在綁定模式下,onBind函數被調用時,說明服務以及被前台界面組件綁定。服務組件應根據調用者傳遞的Intent對象,在該函數內加載資源,構建通信對象,等待綁定者的調用。當界面組件完成相關操作時,需會解除與服務組件的綁定。此時,onUnBind函數會被調用,可以在該函數中做一些統計和資源清理工作。

被綁定服務組件的進程狀態,與綁定該服務的界面組件密切相關。如果綁定組件為前台界面組件,則改服務所處的進程即為前台進程。反之也相同。

Android系統不會輕易回收前台進程或者可視進程,所以出於綁定狀態的組件通常也不會被強制停止。對於開發者而言,綁定服務後一定不要忘記選擇在合適的時機接觸綁定,否則將使服務組件停留在前台或可視狀態無法回收,從而浪費系統資源。

在調用模式,當服務組件執行onStartCommand函數時,服務所在的進程為前台進程,擁有最高的優先級。當onStartCommand函數執行完成後,如果沒有顯示的調用stopSelf等相關函數來停止服務組件,那麼該服務組件將會成為後台組件繼續提供服務,直至調用stopSelf函數停止,或者等待系統強行回收。

onStartCommand函數中增加三個返回值和控制參數,用於指定後台服務組件的運行方式,其中最重要的返回值有三個:

START_STICKY —— 系統會對該服務組件負責到底,在強行回收該組件後後,在資源寬裕的時候還會調用onStartCommand函數重新啟動該服務。直到調用stopSelf函數。對於開發者而言,編寫返回值為START_STRICKY,一定要在合適的時機調用stopSelf函數主動關閉服務,否則會無限期的消耗系統資源。

START_NOT_SRICKY —— 說明系統可以無條件的回收該組件,而無需關注服務是否完成,也不需要負責服務的重新啟動。

START_REDELIVER_INTENT —— 則意味著需要保障該服務組件能夠完整的處理完每一個Intent對象。

觸發器組件的生命周期:

觸發器的生命周期是最短暫的,其整個生命周期就是構造觸發器對象,然後執行onReceive函數。對於執行完onReceive函數,系統會立即出發銷毀觸發器的組件對象,回收其占用的資源。

生命周期內,onReceive函數內部不能夠處理耗時任務。

數據源組件的生命周期

理論上來說,數據源組件沒有所謂的生命周期,因此數據源組件的狀態不作為進程優先級的判斷依據。所以系統在回收進程資源時,並不會將數據源的銷毀事件告知開發者。

但Android會在構造數據源組件時調用onCreate函數。開發者可以在該函數中數據化數據源所需的數據庫或者其他數據內容。

由此可知,在數據源組件中部署延遲寫入等寫優化策略是不合適,因為數據源組件可能會被系統靜默回收,從而導致未持久化的寫入數據丟失。所以在數據源組件的實現中,寫優化策略應該交由上層調用去實現,或者下層數據存儲者去處理。

一旦數據源組件構造出來,就會保持長期運行的狀態直至其所在的進程被系統回收。所以不要再數據源組件中緩存過多的數據,以免占用內存空間。

觀察者事件:

通常如果在onResume與onPause中,接收到觀察者事件可以安全的執行後續觀察者事項。盡量確保組件的觀察者事件只處理當前界面處於前台狀態下的事物,而可視狀態甚至後台狀態下的事物,不可以依賴觀察者事件來處理。
因為觀察者事件並不能確保在組件生命之間可達。觀察者事件只應該在組件可見的生命周期內執行監聽,其余的數據更新需要依賴於組件的生命周期方法。
比如onStart,onStop,onResume,onPause等。過度依賴於觀察者事件,將導致將必要的功能與觀察者事件耦合。

觀察者事件的add和remove需要成對出現,否則會引發內存洩露。

 

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