考察內容:
- 瞭解Context的作用
- 熟悉Context的初始化流程
- 深入理解不同應用組件之間Context的區別
回答幾個問題:
- 應用裏面有多少個Context?不同的Context之間有什麼區別?
- Activity裏面的this和getBaseContext有什麼區別?
- getApplication和getApplicationContext有什麼區別?
- 應用組件的構造,onCreate、attachBaseContext調用順序?
Context是一個抽象類
public abstract calss Context{
public abstract Resources getResources();
public abstract Object getSystemService(String name);
public abstract void startActivty(Intent intent);
public abstract void sendBroadcast(Intent intent);
......
}
其實現都在ContextImpl中
class ContextImpl extends Context{
final ActivityThread mMainThread; //核心類
final LoadedApk mPackageInfo; //安裝包信息
private final ResourcesManager mResourcesManager; //系統資源相關
private final Resources mResources;
private Resoures.Theme mThreme = null; //主題相關
private PackageManager mPackageManager; //包管理
//系統服務緩存
final Object] mServiceCache = SystemServiceRegistry.createServiceCache();
}
正是因爲有了Context這些應用組件纔有意義,它們才能訪問系統服務、訪問系統資源,如果沒有Context那麼Activty不過是一個普通的java對象。
Context是在哪裏創建的?
哪些組件有自己的Context?
- Application
- Activity
- Service
(Broadcast、ContentProvider是沒有自己的Context的)
Application Context
【Application Context的初始化】:
Application Context是跟隨Application一起初始化的,而Application又是跟隨應用進程的啓動一起初始化的。應用進程的啓動是怎樣的呢?先是zygote創建應用進程,應用進程啓動後會執行一個java類的入口函數,也就是ActivityThread的main函數。這個函數會向AMS報告 :我已經啓動好了。AMS收到之後就會下一道命令:創建Application。
AMS讓應用創建Application,應用端的處理函數如下:
private void handleBindApplication(AppBindData data){
//先創建一個Application對象
Application app = data.info.makeApplication(...);
//然後調用它的onCreate回調
app.onCreate();
}
public Application makeApplication(...){
//先創建一個Context:實現就是newContextImpl(...)
ContextImpl appContext = ContextImpl.createAppContext(...);
Application app;
//然後再創建Application對象,傳入appContext參數
app = mActivityThread.mInstrumentation.newApplication(appContext);
return app;
}
//創建Application對象:
application newApplication(ClassLoader cl, String className, Context context){
//先用classLoader對加載Application類
return newApplication(cl.loadClass(className), context);
}
Application newApplication(Class<?> clazz, Context context){
//然後再調用newInstance
//newInstance就會去調用類的構造函數,從而得到Application對象
Application app = (Application)clazz.newInstance();
//最後結app附上context
app.attach(context); //將調用attachBaseContext(context);
return app;
}
【Application的繼承關係】:
public class Application extends ContextWrapper{
......
}
public class ContextWrapper extends Context{
Context mBase;
protected void attachBaseContext(Context base){
mBase = base;
}
public Context getBaseContext(){
return mBase;
}
@Overrid
public Resources getResources() {
return mBase.getResources();
}
@Override
public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
}
Application本身就是一個Context,怎麼裏面還包了一個Context呢?這是爲什麼呢?我們可以看到關於Context的所有調用其實都轉手丟給了裏邊的mBase對象,這是一個典型的靜態代理模式。如果我們用反射換掉了裏面的mBase對象會怎樣呢?比如調用getSystemService函數,結果有可能會跳轉到另一個Context的實現裏面,它就可以對返回的SystemService管理對象做一些手腳。這個機制一般在插件裏會用到。
【Application的結論】:
- 繼承關係:Application<-ContextWrapper<-context
- 調用順序:->attachBaseContext->onCreate
- ContextWraper裏面包含一個Context,調用都委託給它了
Activity Context
【Activty Context的初始化】:
Activity的Context是跟隨Activity的啓動的時候一起初始化的:
private Activity performLaunchActivity(){
Activity activity = null;
//創建Actvity對象
activity mInstrumentation.newActivity();
//獲取之前創建好的application
Application app = r.packageInfo.makeApplication();
//爲Activity創建一個Context:實現就是new ContextImpl()
Context appContext = createBaseContextForActivity(r, activity);
//把appContext和application附給activity
activity.attach(appContext, app, ...); //將調用attachBaseContext(context);
//調用Activity的生命週期函數
activity.onCreate();
return activity;
}
public Activity newActivity(ClassLoader cl, String className){
//先用ClassLoader加載Activity類,然後用newInstance就會去調用Acivity的構造函數,從而得到Activity的對象
return (Activity)cl.loadClass(className).newInstance();
}
【Activty的類繼承關係】:
public class Activity extends ContextThemeWrapper{
...
}
public class ContextThemeWrapper extends ContextWrapper{
private int mThemeResource;
private Resources.Theme mTheme;
private LayoutInflater mInflater;
private Configuration mOverrideConfiguration;
private Resources mResources;
}
public class ContextWrapper extends Context{
Context mBase;
......
}
【Activity的結論】:
- Activity<-ContextThemeWrapper<-ContextWrapper
- 調用順序,->attachBaseContext->onCreate
Service Context
【Service Context的初始化】:
private void handleCreateService(CreateServiceData data) {
Servie service = null;
//通過classLoader加載Service的類,然後調用newInstance
//newInstance將調用Service的構造函數從而獲得一個Service對象
servie = (Service)cl.loadClass(data.info.name).newInstance();
//創建一個Context:實現就是new ContextImpl(...)
ContextImpl context = ContextImpl.createAppContext(this, packageInfo)
context.setOuterContext(service);
//獲取之前創建的application對象
Application app = packageInfo.makeApplication();
//把context和application附給service
service.attach(context, app); //將調用attachBaseContext(context);
//調用Service生命週期
servcie.onCreate();
}
【Service的繼承關係】:
public abstract class Service extends ContextWrapper{
......
}
BroadcastReceiver
public abstract class BroadcastReceiver {
public abstract void onReceive(Context context, Intent intent);
......
}
【廣播結論】:
廣播是一個抽象類,它沒有繼承Context抽象類,也沒有關於Context的全局變量,只有一個onReceive抽象函數,而且這個函數帶了一個參數:Context。如果是動態註冊的廣播,那麼這個Context就是用context.registeReceiver註冊廣播時所用的context;如果是靜態註冊 的廣播,它也不是Activty Context,而是以Application爲mBase的ContextWrapper。
ContentProvider
public abstract class ContentProvider {
private Context mContext = null;
......
}
ContentProvider跟廣播一樣,也沒有繼承什麼ContextWrapper,不過它裏面有一個mContext成員變量,它是ContextProvider初始化的時候外面傳進來的,傳的是Application Context。隨便提一下:ContentProvider的初始化雖然是在Application的構造函數以及attachBaseContext之後,但是它是在application.onCreate()之前調用的。也就是說ContentProvider它的onCreate是比application.onCreate要早。
回答幾個問題:
- 應用裏面有多少個Context?不同的Context之間有什麼區別?
a)Activty的數個+Service的個數+Application的個數。應用可能是多進程的,因此Application可能有多個。區別:Activty因爲要顯示UI,因此它繼承了ContextThemeWrapper,而Service和Application這種非UI組件則直接繼承ContextWrapper。 - Activity裏的this和getBaseContext有什麼區別?
答:因爲Activty是繼承了Context,所以this就是返回Activity對象自己;而getBaseContext返回的是ContextWrapper裏面的mBase。 - getApplication和getApplicationContext有什麼區別?
答:getApplicationContext()是context裏的一個抽象函數,而getApplication()是Activty和Service裏特有的——它在別的地方不能用,比如在廣播的onReciever(context)中的context是不能調getApplication()的,只能調getApplicationContext()。 - 應用組件的構造,onCreate、attachBaseContext調用順序?
答:組件構造函數->attachBaseContext->onCreate
迴歸:談談你對Context的解理
- 說清楚Context的作用
a)Context是應用的上下文,有了Context應用組件就方便去訪問系統資源、調用系統服務 - 說出應用中有幾種Context,各自繼承關係
- 說一下Context的初始化流程