Android是用Java語言來編寫和,然而Android卻需要壹個完整的Android工程環境,在這個環境下,我們熟悉的Activity、Service、ContentPrivoder等系統組件才能有自己各自的上下文環境,也就是Context。Context是維持Android應用的核心功能類,是整個Android系統交互的核心。
Context的繼承結構從圖中可以看到,直系子類有兩個,壹個是ContextWrapper,壹個是ContextImpl。那麽從名字上就可以看出,ContextWrapper是上下文功能的封裝類,而ContextImpl則是上下文功能的實現類。而ContextWrapper又有三個直接的子類,ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是壹個帶主題的封裝類,而它有壹個直接子類就是Activity。
在這裏我們至少看到了幾個所比較熟悉的面孔,Activity、Service、還有Application。由此,其實我們就已經可以得出結論了,Context壹***有三種類型,分別是Application、Activity和Service。這三個類雖然分別各種承擔著不同的作用,但它們都屬於Context的壹種,而它們具體Context的功能則是由ContextImpl類去實現的。
壹種比較特殊的情況是Dialog要求在Activity的Context中彈出,而壹些全局的例如網絡終端的Dialog需要什麽特殊權限。
2. Application類在項目開發中的使用
首先在項目目錄下壹個Java類繼承Application類,實現是onCreate()方法。這個類可以做APP的全局初始化工作,比如圖片加載框架的全局配置信息設置。
public class AndroidApplication extends Application {
private static AndroidApplication instance;
@Override
public void onCreate() {
super.onCreate();
instance = this;
}
public static AndroidApplication getInstance(){
return instance;
}
}
然後千萬不要忘了在Android項目的Manifest文件中指定Application的實現類,不然系統會創建壹個默認的Application類。
<application
android:name=".AndroidApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
3. Application類或Context類的誤用情況
1. 用Application緩存數據
因為Application會因為進入background後內存不足被系統幹掉,進入後系統會重現創建壹個Application類,而導致緩存在Application類裏的數據全部初始化而丟失。
2. 錯誤的獲取全局Context對象的方式
public class AnddroidApplication extends Application {
private static AnddroidApplication app;
public static AnddroidApplication getInstance() {
if (app == null) {
app = new MyApplication();
}
return app;
}
}
上面這種方式如果是單純的Java工程可能沒有問題,但是在Android裏這樣說大錯特錯的。因為Application是系統組件,系統組件實例是要由系統去創建的,如果我們這裏直接創建壹個,不過是簡單的Java對象而已,不具備任何Context能力,也無法進行任何Context操作。標準的寫法就本文的第壹段示意代碼那樣。
3. 在控件的構造方法中獲取Context或者做其他視圖操作
寫過Android的同學應該知道自己或者看別人dome都很少或者基本看不到在控件構造函數內進行初始化,獲取參數等這些操作吧!是的,這樣做是很容易出難以發現的Bug的。具體原因是在ContextWrapper類的源碼中,他有壹個attachBaseContext()方法,這個方法會將傳入的壹個Context參數賦值給mBase對象,之後mBase對象就有值了。而我們又知道,所有Context的方法都是調用這個mBase對象的同名方法,那麽也就是說如果在mBase對象還沒賦值的情況下就去調用Context中的任何壹個方法時,就會出現空指針異常,上面的代碼就是這種情況。