標籤:
<application>節點是AndroidManifest.xml檔案中必須持有的一個節點,它包含在<manifest>節點下。通過<application>節點的相關屬性,我們可以聲明Android應用程式的相關特性。這個節點包含所有應用程式組件的節點,包括Activity,服務,廣播接收器和內容提供者,並且包含了一些可能影響所有組件的屬性。這些屬性中的其中一些又會作為預設值而被設定到應用程式組件的相同屬性上,比如icon,label,permission,process,taskAffinity和allowTaskReparenting等,而其他的一些值則作為應用程式的整體被設定,並且不能被應用程式組件的屬性覆蓋,比如debuggable,enabled,description和allowClearUserData等。
1.<application>節點配置
一般來說,在產生Android應用程式的時候,預設的AndroidManifest.xml檔案中就已經包含了一些預設的<application>節點,其中包含應用程式的基本屬性。現在我們就來看看<application>節點資訊的全集,代碼如下:
<application android:allowTaskReparenting=["true"|"false"]
android:backupAgent="string"
android:debuggable=["true"|"false"];
android:description="string resource"
android:enabled=["true"|"false"]
android:hasCode=["true"|"false"]
android:hardwareAccelerated=["true"|"false"]
android:icon="drawable reource"
android:killAfterRestore=["true"|"false"]
android:label="string resource"
android:logo="drawable resource"
android:manageSpaceActivity="string"
android:name="string"
android:permission="string"
android:persistent=["true"|"false"]
android:process="string"
android:restoreAnyVersion=["true"|"false"]
android:taskAffinity="string"
android:theme="resource or theme">
</application>
2.如何?Application類
首先要介紹的是android:name屬性,它指的是Application類的子類,當應用程式進程被啟動的時候,由android:name屬性指定的類將會在所有應用程式組件(activity,服務,廣播接收器,內容提供者)被執行個體化之前執行個體化。
一般情況下,應用程式無需指定這個屬性,Android會執行個體化Android架構下的applicaiton類。
然而,在一些特殊的情況下,比如希望在應用程式組件啟動之前就完成一個初始化工作,或者在系統低記憶體的時候做一些特別的處理,就要考慮實現自己的Application類的一個子類。
在Android系統提供的系統應用中,就有一個實現了自己的Application執行個體,這個應用程式就是Launcher。我們可以仿照它來實現一個自己的Application類,具體步驟如下。
①建立一個叫做ApplicationTest的項目,並且在預設產生的MainActivity裡的onCreate()方法中添加一行代碼來輸出一條日誌。這樣就可以看到Application建立時間,具體代碼如下:
public class MainActivity extends Activity { private static final String TAG="MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.e(TAG,"MainActivity is created"); }}
②實現自己的MyApplication類,代碼如下:
public class MyApplication extends Application { private static final String TAG="MyApplication"; @Override public void onCreate() { super.onCreate(); Log.e(TAG,"MyApplication is created"); }}
③將MyApplication添加到資訊清單檔AndroidManifest.xml中<application>內android:name中
可以看出來,Android先建立的MyApplication,最後才建立的MainActivity。
3.Application提供的函數及其用法
android.app.Application類提供了許多類似onCreate()的方法,它們會在不同的情境下被Android架構回調。與此同時,Application類還提供了一些監控的函數,用於監視本應用中組件的生命週期。如下表所示:
| 方法名稱 |
傳回值 |
註解 |
| onConfigurationChanged(Configuration newConfig) |
void |
如果組件正在運行時裝置配置(包括語種,方向,網路等)發生改變,則由系統調用此方法通知應用程式 |
| onCreate() |
void |
當應用程式正在啟動時,並且在建立任何其他應用程式物件之前,調用此方法。由於花費在此功能上的時間直接影響了啟動一個進程中首個Activity服務或者接收器的速度,所以儘可能快地執行(例如使用緩慢的初始化狀態)。如果你重寫了這個方法,需要確保調用super.onCreated() 需要注意的是,在實際應用程式中,如果你的應用程式中的某些組件指定了一個process屬性(進程),並且此進程並不存在,那麼Application的onCreate()回調就會被調用,換句話說,此方法可能會被多次調用 |
| onLowMemory() |
void |
當整個系統正在低記憶體運行時,並且希望應用程式縮減使用記憶體的時候,系統調用此方法通知應用程式。但調用此方法的準確點沒有定義時,通常它將在所有後台進程已經終止的時間附近發生。 應用程式可執行此方法來釋放任何緩衝或其擁有的不必要的資源。系統在從此方法中返回後運行記憶體回收操作。 |
| onTerminate() |
void |
此方法在模擬進程環境中使用,不在生產Android裝置上調用,在生產Android裝置上,可以通過簡單地終止進程來移除進程。進行移除工作時,則不執行任何使用者代碼(包括此回調) |
| onTrimMemory() |
void |
回收記憶體的時候調用。例如,當它進入後台並且沒有足夠記憶體保持許多後台進程運行時。 |
監控回調介面 registerComponentCallbacks unregisterComponentCallbacks |
void
void |
在應用程式中註冊一個ComponentCallbacks介面。在Activity生命週期發生改變之前,通過此介面的各個方法通知應用程式。使用這個介面,我們可以在Activity生命週期發生改變之前做一些必要的處理 需要大家注意的是,必須確保在未來恰當的時候使用unregisterComponentCallbacks(ComponentCallbacks)移除ComponentCallbacks對象,它是我們之前用registerComponentCallbacks(ComponentCallbacks)註冊的。 |
接下來,我們通過一些執行個體來說明如何使用這些方法和介面
①使用onConfigurationChanged()方法監聽系統配置更新
onConfigurationChanged()方法的函數原型如下:
public void onConfigurationChanged(Configuration newConfig){}其中newConfig參數表示新的裝置配置
onConfigurationChanged()方法是一個回調介面,在裝置配置發生變化時由Android系統調用。與此同時,Android系統會通過參數(newConfig)傳給應用程式,由應用程式處理這個變化。注意,不同於Activity,其他組件在一個配置改變時從不重新啟動,它們孫弱自己處理改變的結果。這裡所述的“配置”如下表所示:
| 配置項 |
註解 |
| fontScale |
表示當前的系統的字型縮放比例,它是基於像素密度縮放的。 注意,在使用使用者模式編譯出來的系統韌體中,不包含修改此項配置的介面,只能通過編程的方法去改變。 資料類型:浮點型 |
| hardKeyBoardHidden |
指示硬鍵盤是否被隱藏起來,此配置項有3個取值,具體如下所示。 0.HARDKEYBOARDHIDDEN_UNDEFINED(Android無法識別的鍵盤狀態) 1.HARDKEYBOARDHIDDEN_NO(硬鍵盤可用) 2.HARDKEYBOARDHIDDEN_YES(硬鍵盤被隱藏) 資料類型:整型 |
| keyboard |
指示添加到裝置上的是哪個種類的鍵盤,此配置項有以下4個取值 0.KEYBOARD_UNDEFINED(Android無法識別的鍵盤) 1.KEYBOARD_NOKEYS(無按鍵鍵盤) 2.KEYBOARD_QWERTY(打字機鍵盤) 3.KEYBOARD_12KEY(12鍵鍵盤) 資料類型:整型 |
| keyboardHidden |
指示當前是否有鍵盤可用。如果在有硬鍵盤的Android裝置中,硬鍵盤被收合,而仍有軟鍵盤,則認為鍵盤是可用的。這個欄位有如下3個取值。 0.KEYBOARDHIDDEN_UNDEFINED(Android無法識別的鍵盤狀態) 1.KEYBOARDHIDDEN_NO(仍有軟鍵盤可見) 2.KEYBOARDHIDDEN_YES(所有的軟鍵盤都被隱藏)。 資料類型:整型 |
| locale |
定義了裝置的語言環境。它包含了國家以及語言資訊,這些資訊被包含在一個java.util.Locale類型的對象中 |
| mcc |
IMSI的移動國家碼,如果是0,表示未定義。 注意:IMSI是指國際移動使用者識別碼,它儲存在我們的SIM卡中,其總長度不超過15位。 資料類型:整型 |
| mnc |
IMSI的移動網路號,如果是0表示未定義 資料類型:整型 |
| navigation |
指示當前裝置可用的導航方式,它有如下5個取值。 0.NAVIGATION_UNDEFINED(未定義的導航方式) 1.NAVIGATION_NONAV(無導航) 2.NAVIGATION_DPAD(面板導航方式) 3.NAVIGATION_TRACKBALL(軌跡球導航) 4.NAVIGATION_WHEEL(滾輪方式導航) 資料類型:整型 |
| navigationHidden |
用於指示導航是否可用,有如下取值。 0.NAVIGATIONHIDDEN_UNDEFINED 1.NAVIGATIONHIDDEN_NO 2.NAVIGATIONHIDDEN_YES 資料類型:整型 |
| orientation |
指示螢幕方向的標誌,有如下4個取值。 0.ORIENTATION_UNDEFINED(未定義的方法) 1.ORIENTATION_PORTRAIT(豎屏方向,螢幕寬度小於高度) 2.ORIENTATION_LANDSCAPE(橫屏方向,螢幕寬度大於高度) 3.ORIENTATION_SQUARE(正方形螢幕,認為螢幕寬度等於高度) 注意:在視窗管理服務(WindowManagerService)中計算新配置時,orientation的預設配置是ORIENTATION_SQUARE 資料類型:整型 |
| screenHeightDp |
螢幕可用部分的高度 |
| screenLayout |
指示螢幕的整體屬性,它包括兩個部分。 ⒈SCREENAYOUT_SIZE_MASK:標誌螢幕大小的屬性(比如大螢幕,小螢幕等),它有以下5個取值。 SCREENAYOUT_SIZE_UNDEFINED:未定義(值:0) SCREENAYOUT_SIZE_SMALL:小螢幕(值:1,螢幕解析度至少為320*426)。 SCREENAYOUT_SIZE_NORMAL:普通螢幕(值:2,螢幕解析度至少為320*470) SCREENAYOUT_SIZE_LARGE:大螢幕(值:3,螢幕解析度至少為480*640) SCREENAYOUT_SIZE_XLARGE:加大螢幕(值:4,螢幕解析度至少為720*960) ⒉SCREENAYOUT_LONG_MASK:指示螢幕是否比通常情況上更高或者更寬,它有如下3個取值。 SCREENAYOUT_LONG_UNDEFINED:未定義(十六進位值為0) SCREENAYOUT_LONG_YES:是(十六進位值為20) SCREENAYOUT_LONG_NO:否(十六進位值為10) |
| screenWidthDp |
螢幕可用部分的寬度 |
| smallestScreenWidthDp |
在正常操作中,應用程式將會看到最小的螢幕尺寸。這是在豎屏和橫屏中screenWidthDp和ScreenHeightDp的最小值。 |
| touchscreen |
裝置上觸控螢幕的種類,它支援如下取值。 0.TOUCHSCREEN_UNDEFINED(未定義模式) 1.TOUCHSCREEN_NOTOUCH(無觸屏模式) 2.TOUCHSCREEN_STYLUS(手寫筆模式) 3.TOUCHSCREEN_FINGER(手指觸屏模式) |
| uiMode |
UI模式的位元遮罩,目前有兩個欄位。 ⒈UI_MODE_TYPE_MASK:定義了裝置的整個UI模式,它支援如下取值。 UI_MODE_TYPE_UNDEFINED:未知模式 UI_MODE_TYPE_NORMAL:通常模式 UI_MODE_TYPE_DESK:帶底座模式‘ UI_MODE_TYPE_CAR:車載模式 ⒉UI_MODE_NIGHT_MASK:定義了螢幕是否在一個特殊模式中。它支援如下取值。 UI_MODE_NIGHT_UNDEFINED:未定義模式 UI_MODE_NIGHT_NO:非夜晚模式 UI_MODE_NIGHT_YES:夜晚模式 |
下面我們通過一個執行個體來說明當裝置配置發生變化的時候,系統如何通過onConfigurationChanged回調介面來通知應用程式的。
㈠為前面的應用程式添加一個名叫ConfigApplication的Application的子類,並實現onCreate()方法及onConfigurationChanged()方法。在onCreate()方法中,我們會擷取應用程式在建立之初所擁有的配置資訊。而在onConfigurationChanged()方法中,則可以添加一些代碼以便用日誌的方式來即時體現配置更新。相關代碼如下:
public class ConfigApplication extends Application { private static final String TAG="ConfigApplication"; private Configuration mConfiguration; @Override public void onCreate() { super.onCreate(); this.mConfiguration=getResources().getConfiguration();//擷取配置資訊 Log.e(TAG,"onCreate::infomation:orientation="+this.mConfiguration.orientation); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //列印更新後的配置資訊 Log.e(TAG,"onConfigurationChanged:infomation:orientation="+newConfig.orientation); }}
㈡按前文所述,將ConfigApplication配置到AndroidManifest.xml檔案中。
㈢裝置運行應用程式,就可以看到如下的日誌資訊了。
對於日誌,說明如下:
日誌資訊的第一行是初始狀態下的方向配置,通過我們知道最初的方向值是1。而根據前面的表,可知當前是豎屏方向。
日誌資訊的第五行是切換橫屏後,Android系統回調了我們實現的onConfigurationChanged()方法,這時系統配置已經發生了改變,因此這裡的日誌列印了當前的螢幕方向是2,也是就橫屏。
建議:由於基類onConfigurationChanged()方法中實現了對一些回調介面的調用,所以如果我們重寫了這個方法,那麼為了維持原Application類的行為,建議在重寫的方法入口調用super.onConfigurationChanged(newConfig)。
②使用onCreate()完成應用程式初始化
onCreate()方法的原型為:
public void onCreate(){}
如前面的表所示,onCreate()方法是一個回調介面。Android系統會在應用程式啟動的時候,在任何應用程式組件(Activity,服務,廣播接收器,內容提供者)被建立之前調用這個介面。
需要注意的是,這個方法的執行效率會直接影響到啟動Activity,服務,廣播接收器,或者內容提供者的效能,因此該方法應儘可能快地完成。
最後,如果實現了這個回調介面,請前晚不要忘記調用super.onCreate(),否則應用程式會報錯。
前面我們實現了Appplication類的子類------Configuration,並且也已經實現了自身的onCreate()方法。這裡來做個小實驗,讓大家更清楚這些知識。
現在,在原始碼的onCreate()方法中加入一個大約20秒的等待,以此來類比在onCreate()方法中做了過於繁重的工作而導致該方法長時間無法完成的情況,修改後的代碼如下:
public class ConfigApplication extends Application { private static final String TAG="ConfigApplication"; private Configuration mConfiguration; @Override public void onCreate() { super.onCreate(); this.mConfiguration=getResources().getConfiguration();//擷取配置資訊 Log.e(TAG,"onCreate::infomation:orientation="+this.mConfiguration.orientation); SystemClock.sleep(20000);//沉睡20秒 } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //列印更新後的配置資訊 Log.e(TAG,"onConfigurationChanged:infomation:orientation="+newConfig.orientation); }}
此時運行程式,程式就會崩潰,當然,在真實的裝置上,是可以等待的,有的並不會造成崩潰,比如經在小米上測試50秒,程式並沒有崩潰,而是等待下去,直到程式正常。當這樣會造成不好的使用者體驗。所以在以後開發過程中,要充分考慮到這些容易出錯的情況。
③使用onLowMemory()回調方法監視低記憶體
該方法的原型為:
public void onLowMemory(){}
當整個系統在低記憶體運行時,將調用該方法。
好的應用程式會實現該方法來釋放任何緩衝或者其他不需要的資源。系統從該方法返回之後,將執行一個記憶體回收操作。
④使用registerActivityLifecycleCallbacks()註冊可以監視Activity生命週期的介面
registerActivityLifecycleCallbacks()方法的原型為:
public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback){}
在該方法中,參數callbacks表示Activity生命週期的介面。
從Android4.0以後,Android SDK為應用程式提供了一套完整的介面以便監視與本Application相關的Activity的生命週期(建立,啟動以及暫停等),它的名字叫做ActivityLifecycleCallbacks。只要在Application中通過registerActivityLifecycleCallbacks()方法將介面註冊上,它就會通過ActivityLifecycleCallbacks提供應用程式中相關的Activity生命週期資訊。下表列出了這些介面以及用途。
| 方法原型 |
參數說明 |
用途 |
| abstract void onActivityCreated(Activity activity,Bundle savedInstanceState) |
activity:建立的Activity執行個體 savedInstanceState:建立該Activity時所帶的資訊(一個Bundle執行個體) |
在應用程式建立Activity之前調用,用於通知介面實現者Activity將要被建立。 |
| abstract void onActivityDestroyed(Activity activity) |
activity:銷毀的Activity執行個體 |
在應用程式銷毀Activity之前調用,用於通知介面實現者Activity將要被銷毀。 |
| abstract void onActivityPaused(Activity activity) |
activity:暫停Activity執行個體 |
在應用程式暫停Activity之前調用,用於通知介面實現者Activity將要被暫停。 |
| abstract void onActivityResumed(Activity activity) |
activity:恢複的Activity執行個體 |
在應用程式正在恢複Activity之前調用,用於通知介面實現者Activity將要被恢複。 |
| abstract void onActivitySaveInstanceState(Activity activity,Bundle outState) |
activity:正在執行狀態儲存的的Activity執行個體 outState:需要儲存的Activity狀態 |
指示當前Activity正在儲存自己的狀態,這些狀態包含在outState中。 |
| abstract void onActivityStarted(Activity activity) |
activity:啟動的Activity執行個體 |
在應用程式正在啟動Activity之前調用,用於通知介面實現者Activity將要被啟動。 |
| abstract void onActivityStopped(Activity activity) |
activity:停止的Activity執行個體 |
在應用程式正在停止Activity之前調用,用於通知介面實現者Activity將要被停止。 |
特別提醒:從介面定義中,我們可以知道如下資訊。
Ⅰ這些介面都是抽象的,因此當我們實現ActivityLifecycleCallbacks介面時,就必須實現這些方法,哪怕只是空實現。
Ⅱ這些介面的傳回值都是void,這說明它們只用於通知,別無它用。
另外我們在必要時要調用unregisterActivityLifecycleCallbacks()方法來登出掉原先註冊的介面以免造成不必要的資源浪費。
下面我們通過一個執行個體來說明配置發生變化的時候,系統如何通過onConfigurationChanged()回調介面來通知應用程式,具體的步驟如下所示。
㈠實現自己的Application子類(名叫ALCApplication)。我們將在應用程式建立(onCreate()方法中)時註冊自己的Activity生命週期介面,在程式終止(onTerMinate()方法中)時登出這個介面。當完成這些工作以後,將得到如下所示的代碼:
public class ALCApplication extends Application { private final static String TAG="ALCApplication"; private ActivityLifecycleCallbacks mActivityLifecycleCallbacks=new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { Log.e(TAG,"onActivityCreated"); } @Override public void onActivityStarted(Activity activity) { Log.e(TAG,"onActivityStarted"); } @Override public void onActivityResumed(Activity activity) { Log.e(TAG,"onActivityResumed"); } @Override public void onActivityPaused(Activity activity) { Log.e(TAG,"onActivityPaused"); } @Override public void onActivityStopped(Activity activity) { Log.e(TAG,"onActivityStopped"); } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { Log.e(TAG,"onActivitySaveInstanceState"); } @Override public void onActivityDestroyed(Activity activity) { Log.e(TAG,"onActivityDestroyed"); } }; @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(this.mActivityLifecycleCallbacks); } @Override public void onTerminate() { super.onTerminate(); unregisterActivityLifecycleCallbacks(this.mActivityLifecycleCallbacks); }}
㈡將ALCApplication配置到AndroidManifest.xml中,當配置完成時,最後的結果看起來與類似:
這裡我們通過介面監視Activity從啟動到推出的生命週期。
在這個執行個體中,我們在onTerminate()方法中做了登出介面的工作。但值得注意的是,onTerminate()方法只會在虛擬機器進程中被調用,永遠不會在真實的Android裝置中被調用。
⑤使用registerComponentCallbacks()註冊一個可以用來艦艇Activity生命週期的介面
該方法原型為:
public void registerComponentCallbacks(ComponentCallbacks callback){}
其中參數callback是ComponentCallbacks 介面的一個實現。當Activity的生命週期發生變化時,會通過這個介面通知應用程式。對於所有應用程式來,它是通用的回調API集合的介面。ComponentCallbacks中只包括兩個方法,它們分別是public abstract void onConfigurationChanged(Configuration newConfig)和public abstract void onLowMemory()。 這兩個方法的調用與Application中的同名回調方法的調用條件一樣的。
ComponentCallbacks()和registerComponentCallbacks()方法的用法與ActivityLifecycleCallbacks()和registerActivityLifecycleCallbacks()的用法是一樣的,這裡就不單舉例說明了。
Android資訊清單檔詳解(三)----應用程式的根節點<application>