第三章
<!--[if !supportLists]-->1. <!--[endif]-->Application生命週期
每個Android的應用都有一個Application對象,我們可以使用該對象共享一些狀態,即使我們不繼承Application,提供自己的Application對象,Android平臺也爲我們提供一個默認的Application對象。
生命週期爲:
<!--[if !supportLists]-->1) <!--[endif]-->onCreate在應用程序開始的時候被調用。該方法一定要實現的快。
<!--[if !supportLists]-->2) <!--[endif]-->onLowMemory在系統需要回收應用時調用。可以在這裏清除緩存或者其他釋放內存的操作,這樣做的好處是如果你釋放了足夠多的內存,系統不會停止該應用。
<!--[if !supportLists]-->3) <!--[endif]-->onTerminate在應用被停止時,偶爾被調用
<!--[if !supportLists]-->4) <!--[endif]-->onConfigurationChanged當應用程序運行時設備配置發生變化時調用
Constant |
Value |
Description |
mcc |
0x0001 |
The IMSI MCC has changed, that is a SIM has been detected and updated the Mobile Country Code. |
mnc |
0x0002 |
The IMSI MNC has changed, that is a SIM has been detected and updated the Mobile Network Code. |
locale |
0x0004 |
The locale has changed, that is the user has selected a new language that text should be displayed in. |
touchscreen |
0x0008 |
The touchscreen has changed. Should never normally happen. |
keyboard |
0x0010 |
The keyboard type has changed, for example the user has plugged in an external keyboard. |
keyboardHidden |
0x0020 |
The keyboard or navigation accessibility has changed, for example the user has slid the keyboard out to expose it. Note that despite its name, this applied to any accessibility: keyboard or navigation. |
navigation |
0x0040 |
The navigation type has changed. Should never normally happen. |
orientation |
0x0080 |
The screen orientation has changed, that is the user has rotated the device. |
screenLayout |
0x0100 |
The screen layout has changed. This might be caused by a different display being activated. |
uiMode |
0x0200 |
The global user interface mode has changed. For example, going in or out of car mode, night mode changing, etc. |
screenSize |
0x0400 |
The current available screen size has changed. If applications don't target at least HONEYCOMB_MR2 then the activity will always handle this itself (the change will not result in a restart). This represents a change in the currently available size, so will change when the user switches between landscape and portrait. |
smallestScreenSize |
0x0800 |
The physical screen size has changed. If applications don't target at least HONEYCOMB_MR2 then the activity will always handle this itself (the change will not result in a restart). This represents a change in size regardless of orientation, so will only change when the actual physical screen size has changed such as switching to an external display. |
fontScale |
0x40000000 |
The font scaling factor has changed, that is the user has selected a new global font size. |
<!--[if !supportLists]-->2. <!--[endif]-->用戶啓動一個Android應用的時候,會使用一個唯一的用戶ID去啓動一個新的進程,這樣就能讓每個應用程序有獨立的內存和狀態,以及安全和多任務。
每個進程都有一個主線程(Main Thread),這個主線程一般被稱爲UI Thread。
<!--[if !supportLists]-->3. <!--[endif]-->Choose which processes get the ax
Android平臺會儘可能的保證應用的進程存在,但是因爲資源有限,系統會關閉一些進程。Android平臺通過5個級別去找到哪個進程可以被關閉:
<!--[if !supportLists]-->1) <!--[endif]-->Foreground:用戶正在交互的
<!--[if !supportLists]-->2) <!--[endif]-->Visible:這個不太明白
<!--[if !supportLists]-->3) <!--[endif]-->Service:通過startService啓動的Service
<!--[if !supportLists]-->4) <!--[endif]-->Background:後臺運行的Activity的進程。當有多個進程時,使用LRU
<!--[if !supportLists]-->5) <!--[endif]-->Empty:沒有和任何應用程序組件掛鉤的進程
<!--[if !supportLists]-->4. <!--[endif]-->通過設置android:process的屬性,可以讓一個應用跑在多個進程裏或者多個應用跑在一個進程裏。默認是每個應用一個進程,當多個應用爲了更輕鬆的訪問同一個文件時,可以讓多個應用跑在一個進程裏。但是多個應用跑在同一個進程裏時,會增加快垃圾收集的次數,會影響應用的運行速度。
<!--[if !supportLists]-->5. <!--[endif]-->Activity的生命週期
<!--[if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter" /> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0" /> <v:f eqn="sum @0 1 0" /> <v:f eqn="sum 0 0 @1" /> <v:f eqn="prod @2 1 2" /> <v:f eqn="prod @3 21600 pixelWidth" /> <v:f eqn="prod @3 21600 pixelHeight" /> <v:f eqn="sum @0 0 1" /> <v:f eqn="prod @6 1 2" /> <v:f eqn="prod @7 21600 pixelWidth" /> <v:f eqn="sum @8 21600 0" /> <v:f eqn="prod @7 21600 pixelHeight" /> <v:f eqn="sum @10 21600 0" /> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect" /> <o:lock v:ext="edit" aspectratio="t" /> </v:shapetype><v:shape id="Picture_x0020_1" o:spid="_x0000_i1025" type="#_x0000_t75" alt="Activity生命週期記憶" style='width:442.5pt;height:221.25pt;visibility:visible; mso-wrap-style:square'> <v:imagedata src="file:///C:\Users\hehai\AppData\Local\Temp\msohtmlclip1\01\clip_image001.png" o:title="Activity生命週期記憶" /> </v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
不難看出,其實這些方法都是兩兩對應的,onCreate創建與onDestroy銷燬;onStart可見與onStop不可見;onResume可編輯(即焦點)與onPause;這6個方法是相對應的,那麼就只剩下一個onRestart方法了,這個方法在什麼時候調用呢?答案就是:在Activity被onStop後,但是沒有被onDestroy,在再次啓動此Activity時就調用onRestart(而不再調用onCreate)方法;如果被onDestroy了,則是調用onCreate方法。
這樣大家就應該能夠很容易的記住這些方法了。下面再通過一個比喻來看兩個Activity的切換過程。
我們把Activity比作一本書,我們要看書,首先從書架上取出書(onCreate),然後放到桌上(onStart),接着打開書(onResume),這樣我們就可以看書並可以在書本上寫字了。
如果這時候我們要啓動另一個Activity,也就是要看另一本書,首先我們放下手中的筆或者說合上書(onPause),然後從書架上拿下另一本書(書2:onCreate),然後把書本2放到桌上並打開(書2:onStart、onResume)。
如果書本1被書本2完全蓋住了,即不可見了,就調用書本1的onStop;而如果書本2較小,沒有完全蓋住書本1,則不會調用。
我們還可以把書本1放回書架上,即onDestroy。
另外,還有一點要注意,Activity在處於onPause、onStop、onDestroy狀態下,系統都可以銷燬該Activity所在進程,所以我們在處理一些要保存的數據時,必須在onPause方法中進行,因爲onStop和onDestroy方法不一定會被調用。
<!--[if !supportLists]-->1) <!--[endif]-->onCreate:Activity第一次被創建時調用該方法。應該在這個方法裏做所有的靜態初始化:創建views,list綁定數據等。該方法還提供包含了上次的狀態的Bundle的參數,可以通過這個參數恢復Activity。Always followed by onStart.
<!--[if !supportLists]-->2) <!--[endif]-->onRestart: Activity被stop之後,沒有被destory,但是又被用戶調用時調用這個方法。Always followed by onStart.
<!--[if !supportLists]-->3) <!--[endif]-->onStart: 當Activity變成可見時調用該方法。Followed by onResume if the activity comes to the foreground, or onStop if it becomes hidden.
<!--[if !supportLists]-->4) <!--[endif]-->onResume: 當Activity開始跟用戶交互的時候調用該方法。這時,這個Activity在activity棧的最上面。Always followed by onPause. 覆蓋該方法去更新Activity的視圖,是更新而不是重新創建。可以通過web service取數據然後刷新views。
<!--[if !supportLists]-->5) <!--[endif]-->onPause: 當系統開始恢復前一個activity的時候調用。在這個方法裏一般用來提交未保存的改變到數據庫,停止動畫以及其他消耗CPU的事情。因爲在這個方法未結束之前,要恢復的activity不會調用onResume方法,所以這個方法推薦很快就返回。Followed by either onResume if the activity returns to the front, or onStop if it becomes invisible to the user. 一般請覆蓋該方法,在該方法裏清楚Activity創建的東西,以回收內存。
<!--[if !supportLists]-->6) <!--[endif]-->onStop: 當Activity因爲其他Activity調用了onResume的方法而覆蓋了本Activity不再被可見時調用。當一個新的Activity開始了或者已經存在的Activity被拿到前面時,或者當前這個Activity被destoryed時。Followed by either onRestart if this activity is coming back to interact with the user, or onDestory if this activity is going away.
<!--[if !supportLists]-->7) <!--[endif]-->onDestory: 當該Activity結束時或者系統爲了節約內存零時destory該activity時會調用該方法。可以使用isFinishing方法來判斷是上面的那一種情況。如果是因爲回收內存而被destory,緊接着的是onRestart方法。
<!--[if !supportLists]-->6. <!--[endif]-->Configuration
Configuration類定義了設備的所有配置信息。包括硬件配置,設備方向,屏幕大小,語言設置等等。
當Configuration改變的時候,Android會destory和recreate當前的Activity。
當Configuration改變時,Android會調用onPause、onDestory去destory當前的Activity,然後調用當前的Activity的onCreate、onResume方法重建當前的Activity。同時,instance state也通過onSaveInstanceStat和onRestoreInstanceState這兩個方法保存和恢復。
通過設置android:configChange的值,可以讓Android不銷燬和重建Activity。
<!--[if !supportLists]-->7. <!--[endif]-->Activity的實例狀態(instance state)
Instance state:沒有提交的form表單,selections,Listview的index等數據,與Activity的生命週期一樣。
Persistent state:
Instance state在Android系統destory一個Activity時會保存(Configuration改變或者別的)。在Activity被finish(按Back按鈕)之後不會被保存。
Activity的onRestoreInstanceState(Bundle savedInstanceState)方法和onSaveInstanceState(Bundle outstate) 方法來恢復和保存Activity的實例狀態(instance state)
<!--[if !supportLists]-->8. <!--[endif]-->Noconfiguration instance state
Noconfiguration instance state就是在Activity兩個實例之間傳遞的state,因爲Activity會被destory,然後重建Activity之後可以通過Noconfiguration instance state得到上一個實例的一些狀態。
使用getLastNonConfigurationInstance方法取得上一個實例的noconfiguration instance state
使用onRetainNonConfigurationInstance方法返回你想傳遞的內容
需要注意的事情是實例之間傳遞的狀態可以是任意對象,但是不要有當前Activity的引用,否則這樣會導致Activity不能被回收,造成內存泄露。
不要隨意使用
不要傳遞會跟configuration變化而變化的資源