Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [better practice系列]Android處理好activity正確情況下的生命周期和意外情況下的生命周期淺析

[better practice系列]Android處理好activity正確情況下的生命周期和意外情況下的生命周期淺析

編輯:關於Android編程

前言:

Activity生命周期是每一個Android開發者接觸Android之始就會學習的東西,每個人都會說出點什麼,我想任何一個經驗老道高級語言開發程序員談到生命周期這個概念,總有一種接觸越多體會越深的感覺。

Android是面向對象設計的,Android是面向對象設計的,Android是面向對象設計的。重要的事情先說三遍。Activity到底是對什麼的抽象,我想大家都不敢隨隨便便自己給一個定義。

正文:

首先先貼一張官方正版的生命周期圖:

\

這個圖反映了android在正常情況下activity的生命周期變化。

OK我們先簡單的看一下官方對Activity的描述:

An activity is a single, focused thing that the user can do. Almost allactivities interact with the user, so the Activity class takes care of

creating a window for you in which you can place your UI with{@link #setContentView}. While activities are often presented to the user

as full-screen windows, they can also be used in other ways: as floatingwindows (via a theme with {@link android.R.attr#windowIsFloating} set)

or embedded inside of another activity (using {@link ActivityGroup}).

意思呢就是:activity是單一的、用戶可以操作的東西,基本上所有的activity都和用戶交互,所以activity關心創建一個你可以放置UI的視窗。……

我們可以想象一下activity是對什麼的抽象,而且定義的生命周期關鍵點就是這個東東的某些特殊狀態點。

那我們再回顧一下基礎知識:

activity生命周期中幾個關鍵點所對應的實際場景

1.onCreate

activity開始被創建

2.onRestart

activity被重新啟動

3.onStart

activity被啟動

4onResume

activity進入可見、可交互狀態

5onPause

activity開始暫停

6onStop

activity即將停止

7onDestroy

activity即將銷毀

生命周期的演變在圖中表現的很詳細,再引用google官方的一個表:

 

Method

Description

Killable?

Next

onCreate()

Called when the activity is first created. This is where you should do all of your normal static set up: create views, bind data to lists, etc. This method also provides you with a Bundle containing the activity's previously frozen state, if there was one.

Always followed by onStart().

No

onStart()

onRestart()

Called after your activity has been stopped, prior to it being started again.

Always followed by onStart()

No

onStart()

onStart()

Called when the activity is becoming visible to the user.

Followed by onResume() if the activity comes to the foreground, or onStop() if it becomes hidden.

No

onResume() or

onStop()

onResume()

Called when the activity will start interacting with the user. At this point your activity is at the top of the activity stack, with user input going to it.

Always followed by onPause().

No

onPause()

onPause()

Called when the system is about to start resuming a previous activity. This is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, etc. Implementations of this method must be very quick because the next activity will not be resumed until this method returns.

Followed by either onResume() if the activity returns back to the front, or onStop() if it becomes invisible to the user.

Yes

onResume() or

onStop()

onStop()

Called when the activity is no longer visible to the user, because another activity has been resumed and is covering this one. This may happen either because a new activity is being started, an existing one is being brought in front of this one, or this one is being destroyed.

Followed by either onRestart() if this activity is coming back to interact with the user, or onDestroy() if this activity is going away.

Yes

onRestart() or

onDestroy()

onDestroy()

The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.

Yes

Nothing


表格中用語言描述了生命周期可能的變化,其實還是看圖明顯。接下來集中寫以下幾個問題:

 

正常情況下各個生命周期轉折點做點什麼一些不合理的做法和不合理的原因異常情況下生命周期

正常情況下各個生命周期轉折點做點什麼

onCreate(Bundle savedInstanceState)

Called when the activity is starting. This is where most initialization should go: calling setContentView(int) toinflate the activity's UI, using findViewById to programmatically interact withwidgets in the UI, calling managedQuery(android.net.Uri, String[], String,String[], String) to retrieve cursors for data being displayed, etc.
You can call finish from within this function, in which case onDestroy() willbe immediately called without any of the rest of the activity lifecycle(onStart, onResume, onPause, etc) executing.

以上是API描述,onCreate中應該做一些初始化的工作,而且是絕大多是的實例化工作,言下之意是這裡很適合做實例化工作(應該做),但存在有些特殊的情況(看到這裡你是不會知道特殊情況是什麼的)。而且這些初始化工作主要和界面有關,很多人要說,此處不要做耗時操作,是的,因為界面還沒有可見,耗時操作會托節奏,但這是主要原因嗎?可能阻塞主線程的耗時操作都是不應該在主線程中進行,做一些實例化的行為還談不上耗時,哪怕是反射實現的。

 

void android.app.Activity.onStart()

Called after onCreate — or after onRestart when the activity had been stopped, but is now again being displayed to the user. It will be followed by onResume.

如果從正常的生命周期來看,總會覺得去實現onStart有點多余,需要注意的是,界面此時還是不可見的。不可交互的。不要去做動畫。(不能確定是否是容錯機制,在此處開始一個動畫沒有遇到過crash或者警告,但起碼這時候是看不到的嘛,那就盡量不要在此處做不合理的事情)。

 

void android.app.Activity.onResume()

Called after onRestoreInstanceState,onRestart, or onPause, for your activity to start interacting with the user. This is a good place to begin animations,open exclusive-access devices (such as the camera), etc.

Keep in mind that onResume is not the best indicator that your activity is visible to the user; a system window such as the keyguard may be in front. Use onWindowFocusChanged to know for certain that your activity is visible to the user (for example, to resume a game).

一切和用戶交互的准備應當在此前完成,例如添加各種監聽器,盡量不要拖到這時候再處理。正如API所說,這時候是打開獨占設備或者展示動畫的好時機。但是注意一件事情:此時可能處於鎖屏2333,用onWindowFocusChanged回調來獲知用戶可以看到這個activity了。

 

void android.app.Activity.onPause()

Called as part of the activity lifecycle when an activity is going into thebackground, but has not (yet) been killed. The counterpart toonResume.

When activity B is launched in front ofactivity A, this callback will be invoked on A. B will not be created until A'sonPause returns, so be sure to not do anything lengthy here.

This callback is mostly used for savingany persistent state the activity is editing, to present a "edit inplace" model to the user and making sure nothing is lost if there are notenough resources to start the new activity without first killing this one. Thisis also a good place to do things like stop animations and other things thatconsume a noticeable amount of CPU in order to make the switch to the nextactivity as fast as possible, or to close resources that are exclusive accesssuch as the camera.

In situations where the system needs morememory it may kill paused processes to reclaim resources. Because of this, you should be sure that all of your stateis saved by the time you return from this function. In generalonSaveInstanceState is used to save per-instance state in the activity and thismethod is used to store global persistent data (in content providers, files,etc.)

After receiving this call you will usuallyreceive a following call to onStop (after the next activity has been resumed anddisplayed), however in some cases there will be a direct call back to onResumewithout going through the stopped state.

處於後台了,你可以做一些關鍵數據的保存,免得被內存回收了。

 

 

void android.app.Activity.onStop()

Called when you are no longer visible tothe user. You will next receive either onRestart, onDestroy, or nothing,depending on later user activity.

Note that this method may never be called, in low memory situations where the system does not have enough memory to keep your activity's process running after its onPause method is called.

看起來像是一個完成反注冊的好時機,但注意可能這個方法不會被回調,內存少的時候activity會有直接被干掉的

 

protected void onDestroy ()

Perform any final cleanup before anactivity is destroyed. This can happen either because the activity is finishing(someone called finish() on it, or because the system is temporarily destroyingthis instance of the activity to save space. You can distinguish between thesetwo scenarios with the isFinishing() method.

 

Note: do not count on this method being called as a place for saving data! For example, if an activity is editing data in a content provider, those editsshould be committed in either onPause() or onSaveInstanceState(Bundle), nothere. This method is usually implemented to free resources like threads thatare associated with an activity, so that a destroyed activity does not leavesuch things around while the rest of its application is still running. Thereare situations where the system will simply kill the activity's hosting processwithout calling this method (or any others) in it, so it should not be used todo things that are intended to remain around after the process goes away.

 

Derived classes must call through to thesuper class's implementation of this method. If they do not, an exception willbe thrown.

 

 

 

 

一些不合理的做法和不合理的原因


 

在onCreate()中實現所有的初始化

Activity的onCreate()方法被調用時,Activity處於不可見狀態,如果做動畫等,視圖還不存在呢,所以存在問題;

Activity A 切換到 Activity B,再切換到 ActivityA(Single Instance模式,依舊是原來的實例),實例已經存在,onCreate不再被調用,那Activity A從後台切換至前台時,一些有必要的初始化就沒法實現,也是存在問題的;

 

將所有的初始化都在onStart()中實現

onCreate中:

This is where mostinitialization should go: calling setContentView(int) to inflate the activity'sUI, using findViewById to programmatically interact with widgets in the UI,calling managedQuery(android.net.Uri, String[], String, String[], String) toretrieve cursors for data being displayed, etc.

我想這些內容你不應當忽視。

雖然在onStart()中實現findviewbyid也可行,但我認為這沒有必要,因為每次調用onStart()都會重新實例化view、控件。

一些特殊的初始化、變量的注冊也不應當放在這裡

而且onStart, onResume,onCreate都不是真正visible的時間點,真正的visible時間點是onWindowFocusChanged()函數被執行時。這在onResume()中提及

 

將所有的反注冊都在onStop()中實現

onResume() 的注釋中,建議在 onResume()中打開獨占設備(比如相機),與 onResume() 對應的是 onPause(),所以所有的去初始化操作放在onStop()中執行,並不合適,應當做該做的事情。

而且onStop() 的注釋中明確地寫了:在內存不足而導致系統無法保留此進程的情況下,onStop() 不會被執行。

這裡我們要談一下activity跳轉時兩個activity生命周期的變化,這樣才能更好地理解這些重載函數應該執行些什麼。

Activity間跳轉時(從Activity A跳到Activity B):

1.調用Activity A的onPause(),

2.Activity B的初始化流程(onCreate()--> onStart() --> onResume()),

3.調用Activity A的onStop()

onResume() 的注釋中,建議是在 onResume() 中打開獨占設備(比如相機),與 onResume() 對應的是 onPause() ,關閉相機的操作也應該在此方法中被調用;

考慮一下如下場景:

Activity A打開了相機,此刻跳轉到Activity B,Activity B也要打開相機。

若Activity A的onPause() 在 Activity B啟動後(准確的說是調用Activity B的onResume()之後)再被調用,那Activity B無法打開相機,因為相機作為獨占資源被Activity A占用。

onPause() 的注釋中指出:在這個方法中執行停止動畫等比較耗CPU的操作。如果不先執行這些操作,就先啟動新應用,是不合邏輯的;

從用戶體驗的角度來分析,最後調用onStop()比較合理,當用戶觸發某事件切換到新的Activity,用戶肯定是想盡快進入新的視圖進行操作,而調用onStop()是會耗時的(即使很短)。

底層執行Activity A的onPause()時,有一定的時間限制的,當ActivityManagerService通知應用進程暫停指定的Activity時,如果對應的onPause()在500ms內還沒有執行完,ActivityManagerService就會強制關閉這個Activity。如下就是對應的onPause()執行超時常量定義:

// How long we wait until giving up on the last activity to pause.

//This is short because it directly impacts the responsiveness of startingthe

// next activity.

static final int PAUSE_TIMEOUT = 500; // 定義在ActivityStack.java中

 

 

這裡總結一下,一般我們可以這樣做:

onCreate函數:注冊你要用到的變量,比如說service,receiver,這些變量是無論你的Activity是在前台還是在後台都能夠被響應到的,調用setContentView()函數初始化布局信息。

 

onStart函數:注冊一些變量。這些變量必須在Android Activity類在前台的時候才能夠被響應(或者這樣說更明確,變量的注冊更應當放在onCreate中,但是有些變量的注冊必須在activity處於前台時才可行,這些則放在onStart中)。

 

onResume函數:調用一些刷新UI的函數,每當Activity調用到這裡時就要刷新一下UI各控件的狀態。

 

onPause函數:一般是做一些變量的設置,或者保存,因為這個時候Activity馬上就要切到後台處理,可能有些變量就要被釋放掉或者狀態要做些相應的調整。

 

onStop函數:反注冊在onStart函數中注冊的變量。

 

onDestory函數:反注冊在onCreate中注冊的變量  

異常情況下的生命周期,我們應該做哪些額外的事情:

這些異常情況包括: configure變化,內存回收等等。   各位可能一下子就想到了屏幕旋轉等情況。具體的生命周期變化就不繪制了,難以很好的描述。這些情況下我們想做的是優化體驗,最基本的一件事情就是避免一些數據和狀態的丟失。   保存應當實現onSaveInstanceState(Bundle bundle)函數,將要保存的數據保存到Bundle中。   恢復推薦使用onRestoreInstanceState(Bundle bundle)函數,也可以在onCreate中實現,但需要注意非空判斷。   和生命周期相關的一個很重要的內容是內存洩漏,限於精力本篇就不扯了    

 

 

 

 

 

 

 

 

 

 

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