1. Application 的概述
??每個(gè)App里面都有一個(gè)Application惭蟋,但是我們?yōu)槭裁催€要自定義一個(gè)Application類(lèi)呢笤喳?我們知道當(dāng)App啟動(dòng)的時(shí)候得糜,系統(tǒng)會(huì)自動(dòng)加載并初始化Application類(lèi)艘虎。其實(shí)Google 并不希望我們?nèi)プ远xApplication類(lèi)装获。基本上只有需要做一些全局初始化的時(shí)候可能才需要用到自定義Application光羞。
譯文:注意:通常不需要子類(lèi)化應(yīng)用程序绩鸣。在大多數(shù)情況下,靜態(tài)單例可以以一種更模塊化的方式提供相同的功能纱兑。如果你需要一個(gè)全局上下文(例如注冊(cè)廣播接收器),包括Context . getApplicationContext()作為一個(gè)上下文參數(shù)調(diào)用您的單例的getInstance()方法呀闻。
??市場(chǎng)上的App基本上都會(huì)創(chuàng)建自定義App,創(chuàng)建的自定義的Application類(lèi)和一些單例的工具類(lèi)差不多潜慎〖穸啵可是使用歸使用,有不少項(xiàng)目對(duì)自定義Application的用法并不到位铐炫,正如官方文檔中所表述的一樣垒手,多數(shù)項(xiàng)目只是把自定義Application當(dāng)成了一個(gè)通用工具類(lèi),而這個(gè)功能并不需要借助Application來(lái)實(shí)現(xiàn)倒信,使用單例可能是一種更加標(biāo)準(zhǔn)的方式科贬。不過(guò)使用自定義的Application類(lèi)并沒(méi)有什么副作用,它和單例模式一樣都能實(shí)現(xiàn)全局功能鳖悠。
2. 自定義Application
2.1 自定義Application的用途
- 得到一個(gè)Application對(duì)象
- 封裝一些全局性的操作
- 初始化全局性的數(shù)據(jù)
2.2 創(chuàng)建自定義Application
- 自定義Application 方法很簡(jiǎn)單榜掌,首先創(chuàng)建一個(gè)類(lèi)繼承Application類(lèi)就可以了。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
}
}
- 然后在AndroidManifest.xml文件中的application節(jié)點(diǎn)上乘综,引用就可以了
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
指定完成后憎账,當(dāng)我們的程序啟動(dòng)時(shí)Android系統(tǒng)就會(huì)創(chuàng)建一個(gè)MyApplication的實(shí)例,如果這里不指定的話就會(huì)默認(rèn)創(chuàng)建一個(gè)Application的實(shí)例卡辰。剩下的就是自己創(chuàng)建你需要的方法和實(shí)例了胞皱。
3. 自定義Application使用誤區(qū)
在查看官方文檔的時(shí)候邪意,我們可以知道Application屬于Context類(lèi)中的一種。那么我們想要獲得Context中的各種方法是不是也可以通過(guò)getApplication來(lái)獲得呢反砌?
修改代碼抄罕,獲取包名,運(yùn)行代碼:
public class MyApplication extends Application {
public MyApplication() {
String packageName = getPackageName();
Log.d("TAG", "package name is " + packageName);
}
}
getPackageName()這個(gè)方法是Context提供的于颖,結(jié)果發(fā)現(xiàn)是空指針的操作呆贿。
??這是為什么呢?很簡(jiǎn)單的一段代碼怎么會(huì)報(bào)空呢森渐?我們重新回顧一下ContextWrapper類(lèi)的源碼做入,ContextWrapper中有一個(gè)attachBaseContext()方法,這個(gè)方法會(huì)將傳入的一個(gè)Context參數(shù)賦值給mBase對(duì)象同衣,之后mBase對(duì)象就有值了竟块。而我們又知道,所有Context的方法都是調(diào)用這個(gè)mBase對(duì)象的同名方法耐齐,那么也就是說(shuō)如果在mBase對(duì)象還沒(méi)賦值的情況下就去調(diào)用Context中的任何一個(gè)方法時(shí)浪秘,就會(huì)出現(xiàn)空指針異常,上面的代碼就是這種情況埠况。Application方法的執(zhí)行順序是從構(gòu)造方法到attachBaseContext()方法再到onCreate()方法耸携。所以在初始化操作的時(shí)候
Application中方法的執(zhí)行順序如下圖所示:
??Application中在onCreate()方法里去初始化各種全局的變量數(shù)據(jù)是一種比較推薦的做法,但是如果你想把初始化的時(shí)間點(diǎn)提前到極致辕翰,也可以去重寫(xiě)attachBaseContext()方法嘁酿。
修改代碼:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
String packageName = getPackageName();
Log.d("TAG", "package name is " + packageName);
}
}
或者
public class MyApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
String packageName = getPackageName();
Log.d("TAG", "package name is " + packageName);
}
}
4. 常見(jiàn)的Application使用誤區(qū)
??我們?cè)趧?chuàng)建自定義Application的時(shí)候留晚,最常用的方法是去獲得Application實(shí)例乾翔,列舉一段你很熟悉的代碼出來(lái)乾蓬。
public class MyApplication extends Application {
public static MyApplication app;
public static MyApplication getInstance(){
if(app==null){
app= new MyApplication();
}
return app;
}
@Override
public void onCreate() {
super.onCreate();
}
}
??這個(gè)獲取Application單例方法getInstance(),用于獲取MyApplication的實(shí)例,有了這個(gè)實(shí)例之后我們就能獲取MyApplication這個(gè)類(lèi)里面的方法了壁榕。但是因?yàn)锳pplication類(lèi)屬于系統(tǒng)組件矛紫,系統(tǒng)組件的實(shí)例由系統(tǒng)去創(chuàng)建。所以這里new 一個(gè) MyApplication類(lèi)不具備任何獲取Context的實(shí)例牌里,它只是一個(gè)普通的Java對(duì)象颊咬。因?yàn)锳pplication類(lèi)全局只有一個(gè),它本身就是一個(gè)單例二庵,所以不需要再給它加上單例的外衣去保護(hù)它贪染。
修改代碼:
public class MyApplication extends Application {
public static MyApplication app;
public static MyApplication getInstance(){
return app;
}
@Override
public void onCreate() {
super.onCreate();
app = this;
}
}
??getInstance()方法可以照常提供,但是里面不要做任何邏輯判斷催享,直接返回app對(duì)象就可以了,而app對(duì)象又是什么呢哟绊?在onCreate()方法中我們將app對(duì)象賦值成this因妙,this就是當(dāng)前Application的實(shí)例痰憎,那么app也就是當(dāng)前Application的實(shí)例了。