Context做爲Android中的上下文對象,是Android經常使用的類。啓動四大組件、建立視圖、獲取系統服務、訪問資源等都要用到Context。java
從Context有上下文的意思,結合Context的職能。能夠看出,Context在Android中提供了一個「語境」的意義,它提供了應用程序環境的全局信息。在這個「語境」中能夠經過Context使用相應的接口,作符合當前「語境」意義的事。好比,在Activity中建立Dialog、彈出Toast。android
這篇文章將繼續深刻了解Context。app
上面說到,Context意爲上下文,提供了應用程序環境信息。ide
Context做爲一個抽象類,它的實現有Android系統提供。咱們熟知的有ContextImpl、ContextWrapper、Application、Activity、Service等。佈局
從Context的類圖中能夠看出,ContextImpl和ContextWrapper都是繼承自Context,在ContextWrapper中依賴了ContextImpl對象(mBase)。這裏使用了裝飾者模式,ContextWrapper是裝飾類,對ContextImpl進行包裝,經過使用ContextImpl實現功能。學習
Application、Service、ContextThemeWrapper繼承自ContextWrapper,它們也是經過ContextImpl實現功能,同時在ContextWrapper的基礎上添加了本身的功能。此外ContextThemeWrapper中包含了主題相關的方法,Activity繼承自ContextThemeWrapper。ui
在Context的關聯類中能夠看到,Context類有不一樣的實現,有Application、Activity、Service三種。除此以外,還有BroadcastReceiver以及ContentProvider。這兩個組件不是Context的子類,可是對於BroadcastReceiver來講,在onReceive()時會接收一個Context。靜態註冊方式下的BroadReceiver在建立時傳遞的是ReceiverRestrictedContext。this
在Android程序中ActivityThread是應用進程的主線程管理類,Android四大組件最終都是從這裏開始建立。一下就分析一下各個Context的建立過程。spa
在ActivityThread的performLaunchActivity()方法中,建立Application。線程
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
try {
//建立Application
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
}
}
複製代碼
makeApplication是類LoadedApk的成員方法。
/**LoadedApk.java*/
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Application app = null;
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"initializeJavaContextClassLoader");
initializeJavaContextClassLoader();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
//建立ContextImpl對象
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
//建立Application對象
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
//設置ContextImpl的mOuterContext成員變量
appContext.setOuterContext(app);
} catch (Exception e) {
//......
}
mActivityThread.mAllApplications.add(app);
mApplication = app; //賦值
//..........
return app;
}
/**ContextImpl.java*/
//建立ContextImpl對象
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo){
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, null);
context.setResources(packageInfo.getResources());
return context;
}
複製代碼
在makeApplication()方法中建立了Application對象,上面說到過Context都是依賴ContextImpl實現功能,在這裏也建立了ContextImpl對象,將Application保存到了ContextImpl的成員變量mOuterContext,同時Application將mBase指向了ContextImpl對象。
//mBase綁定ContextImpl對象的過程
/**Application.java*/
final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
/**ContextWrapper.java*/
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
//獲取ContextImpl對象
public Context getBaseContext() {
return mBase;
}
複製代碼
在ActivityThread的performLaunchActivity()方法中,建立Activity。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//建立ContextImpl對象
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
//建立Activity
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
}
//......
if (activity != null) {
//......
//設置ContextImpl的mOuterContext成員變量
appContext.setOuterContext(activity);
//綁定ContextImpl
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
if (customIntent != null) {
activity.mIntent = customIntent;
}
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
//......
}
//......
}
//建立ContextImpl對象
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
//......
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig); //ContextImpl.createActivityContext()方法執行了建立過程
//......
return appContext;
}
複製代碼
能夠看到在performLaunchActivity()方法中建立了Activity對象,同時也建立了用於Activity的ContextImpl對象。而且執行了Context的綁定過程。
/**Activity.java*/
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
}
//綁定ContextImpl對象
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
newBase.setAutofillClient(this);
}
//獲取ContextImpl對象
public Context getBaseContext() {
return mBase;
}
複製代碼
在ActivityThread中的handleCreateService()方法中建立Service。
private void handleCreateService(CreateServiceData data) {
try {
//建立ContextImpl對象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service); //設置ContextImpl的mOuterContext成員變量
Application app = packageInfo.makeApplication(false, mInstrumentation);
//綁定ContextImpl對象
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
mServices.put(data.token, service);
//......
}
//......
}
複製代碼
/**Service.java*/
public final void attach( Context context, ActivityThread thread, String className, IBinder token, Application application, Object activityManager) {
attachBaseContext(context); //綁定ContextImpl到mBase
mThread = thread; // NOTE: unused - remove?
mClassName = className;
mToken = token;
mApplication = application;
mActivityManager = (IActivityManager)activityManager;
mStartCompatibility = getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.ECLAIR;
}
/**ContextWrapper.java*/
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
//獲取ContextImpl對象
public Context getBaseContext() {
return mBase;
}
複製代碼
能夠看到在handleCreateService()方法中建立了Service對象,同時也建立了用於Service的ContextImpl對象。而且執行了Context的綁定過程。
以上講到了Application、Activity、Service中Context的建立過程,能夠看到Context的建立過程正好映照了Context的類圖之間的關聯。經過ContextImpl統一實現Context的功能。
Application | Activity | Service | BroadcastReceiver | ContentProvider | |
---|---|---|---|---|---|
顯示對話框 | × | √ | × | × | × |
啓動Activity | - | √ | - | - | - |
建立佈局 | × | √ | × | - | × |
啓動Service | √ | √ | √ | √ | √ |
綁定Service | √ | √ | √ | - | √ |
發送廣播 | √ | √ | √ | - | √ |
註冊廣播 | √ | √ | √ | - | √ |
獲取資源 | √ | √ | √ | √ | √ |
Tips:(√:表示能夠執行;×:表示不能夠執行;-:表示視狀況而定)
從表中能夠看出任何Context都是能夠獲取到資源數據的,這裏的資源就是res目錄下的資源,好比:字符串、顏色、尺寸等。
對於跟UI有關的,只有Activity的Context能夠執行,好比:建立Dialog或者使用LayoutInflater建立佈局。由於UI相關的須要使用主題(Theme),而只有Activity繼承的ContextThemeWrapper擁有主題相關的方法。
對於啓動Activity來講,除了Activity Context之外。其餘的Context啓動Activity時須要加入FLAG_ACTIVITY_NEW_TASK標誌。由於在啓動Activity須要獲取到當前的棧信息。而其餘的Context沒有棧信息,因此這裏加入FLAG_ACTIVITY_NEW_TASK,起到的做用是從新建立一個Activity棧。
BroadcastReceiver分爲靜態註冊和動態註冊,這兩種方式建立BroadCastReceiver實例的過程不同。
經過上面對Contex的相關知識的學習,對Context的建立以及相關類的關聯和使用有了更加清晰的瞭解。在開發中用到的時候可以使用準確。