1. 程式人生 > >ApplicationContext、ActivityContext、ViewContext和ContextImpl(BaseContext)的區別

ApplicationContext、ActivityContext、ViewContext和ContextImpl(BaseContext)的區別

ContextWrapper

  • ContextWrapper 是 ContextImpl(也就是BaseContext) 的包裝,所有對 ContextWrapper 的操作都會用代理到 BaseContext 上。
  • Application和Activity和Service都繼承自ContextWrapper
  • android.content.ContextWrapper#getApplicationContext 獲得Application例項,和Application.this 是同一個物件。因此Activity.getApplicationContext == Application.getApplicationContext == Service.getApplicationContext == Application.this == Activity.getApplication
  • android.content.ContextWrapper#getBaseContext 都獲得的是ContextImpl物件。

Application中BaseContext的建立過程:

  • android.app.LoadedApk#makeApplication,首先判斷Application例項是否存在,如果存在則直接返回,不存在繼續下面步驟。
  • 首先呼叫 android.app.ContextImpl#createAppContext 建立一個ContextImpl例項;
  • 呼叫 android.app.Instrumentation#newApplication 建立一個Application例項;
  • 呼叫 android.app.Application#attach->android.content.ContextWrapper#attachBaseContext 為Application的BaseContext賦值;
  • 最後呼叫 android.app.ContextImpl#setOuterContext 將Application例項賦值給ContextImpl的mOuterContext,這個mOuterContext的作用:
    • startActivity時,如果是ActivityContext的話,就不需要加 FLAG_ACTIVITY_NEW_TASK 標記之類的
    • 建立部分SystemService(如:android.content.Context#NOTIFICATION_SERVICE)時,也會用到mOuterContext。具體參考ContextImpl的static塊。
  • 因為一個程序中只會有 Application的一個例項,因此Application的BaseContext也只會存在一個。

Activity的BaseContext的建立過程:

  • android.app.ActivityThread#performLaunchActivity
  • android.app.Instrumentation#newActivity 建立Activity例項,直接呼叫Activity的無參構造
  • android.app.ActivityThread#createBaseContextForActivity 為Activity建立BaseContext。
  • android.app.ContextImpl#createActivityContext 建立ContextImpl例項
  • 設定ContextImpl的OuterContext為Activity
  • android.app.Activity#attach->android.content.ContextWrapper#attachBaseContext 為Activity的BaseContext賦值;
  • 因此Activity的BaseContext每次都是新的。

Service的BaseContext的建立過程:

參考:android.app.ActivityThread#handleCreateService 和Activity類似,同樣每次BaseContext都是新的。

ViewContext

參考:android.view.LayoutInflater#createViewFromTag
如果ViewParent使用了不同的Theme之類的,就會和ViewParent使用同一個Context,否則使用 LayoutInflater 例項化時的Context,不過一般ViewContext == Activity.this。ViewContext不可能是ContextImpl,因為在ContextImpl對LAYOUT_INFLATER_SERVICE的獲得是通過getOuterContext,也就是獲得的是Activity,Service或Application。

總結:

  • android.content.ContextWrapper#getBaseContext 都獲得的是ContextImpl物件。
  • Activity.getApplicationContext == Application.getApplicationContext == Service.getApplicationContext == Application.this == Activity.getApplication
  • Application的BaseContext只會存在一個,而Activity和Service的BaseContext每次都是新的.
  • 通常情況下 ViewContext == Activity.this,特殊情況比如:使用LayoutInflater.from(ApplicationContext) inflate的View的ViewContext == Application.this。ViewContext不可能是ContextImpl。