【轉載】Android Context 究竟是什麼?

什麼是Context?

一個Context意味着一個場景,一個場景就是咱們和軟件進行交互的一個過程。好比當你使用微信的時候,場景包括聊天界面、通信錄、朋友圈,以及背後的一些數據。java

那麼從程序的角度來看,Context是什麼?其實一個Activity就是一個Context,一個Service也是一個Context。微信

一個應用程序能夠認爲是一個工做環境,用戶在這個工做環境中會切換到不一樣的場景,這就像一個助理,他可能須要接待客人,可能還要打印文件,還可能接聽電話,而這些就稱之爲不一樣的場景,助理可稱之爲一個應用程序。架構

Activity類的確是基於Context,而Service類也是基於Context。Activity除了基於Context類外,還實現了一些其餘重要的接口,從架構設計的角度看,interface僅僅是某些功能,而extends纔是類的本質,即Activity的本質是一個Context,其所實現的其餘接口只是爲了擴充Context的功能而已,擴充後的類稱之爲一個Activity或Service。app

一個應用程序中應該有多少個Context對象

咱們在應用程序開發中常常會調用Context的一些方法,這些方法看起來彷佛會返回一些全局的對象,而不單單是某個Activity,可能會有點疑問,一個應用程序到底有多少個Context對象呢?好比,Context.getResources()返回該應用程序所對應的Resource類對象,不管從哪一個Activity中調用,都會返回同一個Resource對象。函數

  • 一個Activity就是一個場景(Context),一個Service也是一個場景,因此,應用程序中有多少個Activity或者Service就會有多少個Context對象。
  • getResource()等方法返回的是同一個全局對象。

Context 相關類是怎麼繼承的呢?

Context類及其子類的繼承關係

Context類自己是一個純abstract類。爲了使用方便又定義了Context包裝類-ContextWrapper,ContextWrapper構造函數中必須包含一個真正的Context引用,同時ContextWrapper中有attachBaseContext()用於給ContextWrapper對象中指定真正的Context對象。this

ContextThemeWrapper內部包含了與主題相關的接口,這裏的主題就是指在AndroidManifest.xml中經過Android:theme爲Application或者Activity指定的主題。spa

只有Activity才須要主題,Service不須要主題的,因此Service直接繼承與ContextWrapper。架構設計

ContextImpl類真正實現了Context中全部的函數,咱們所調用的各類Context類的方法其實實現均來自於該類。設計

何時建立Context?

每個應用程序在客戶端都是從ActivityThread類開始的,建立Context對象也是在該類中完成,具體建立ContextImpl類的地方一共有6處:orm

  • PackageInfo.makeApplication()
  • performLaunchActivity()
  • handleCreateBackupAgent()
  • handleCreateService()
  • handleBindApplication()
  • attach()

其中attach()方法僅在Framework進程啓動時調用,應用程序運行時不會調用到該方法。

Application對應的Context

程序第一次啓動時,會展轉調用到makeApplication()方法。具體代碼以下:

ContextImpl appContext = new ContextImpl();
appContext.init(this,null,mActivityThread); .... appContext.setOuterContext(app);

Activity對應的Context

啓動Activity時,Ams會經過IPC調用到ActivityThread的scheduleLaunchActivity()方法,該方法包含兩種參數。一種是ActivityInfo,這是一個實現了Parcelable接口的數據類,意味着該對象是Ams建立的,並經過IPC傳遞到ActivityThread;另外一種是其餘的一些參數。

scheduleLaunchActivity()方法中會根據以上兩種參數構造一個本地ActivityRecord數據類,ActivityThread內部會爲每個Activity建立一個ActivityRecord對象,並使用這些數據對象來管理Activity。

而後會調用handleLaunchActivity(),再調用performLaunchActivity(),該方法中建立ContextImpl的代碼以下:

ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo,r.token,this); appContext.setOuterContext(activity);

在performLaunchActivity()開始執行時,會爲r.packageInfo變量賦值。r.packageInfo對象的PackageInfo對象和Application對應的packageInfo對象是同一個。

Service對應的Context

啓動Service時,Ams會經過IPC調用到ActivityThread的scheduleCreateService()方法,該方法也包含兩種參數。第一種是ServiceInfo,這是實現了一個Parcelable接口的數據類,該對象由AmS建立,並經過IPC傳遞到ActivityThread內部;第二種是其餘參數。

在scheduleCreateService()方法中,會使用以上兩種參數構造一個CreateServiceData的數據對象,ActivityThread會爲其所包含的每個Service建立該數據對象,並經過這些對象來管理Service。

而後在執行handleCreateService()方法,建立ContextImpl對象代碼以下:

ContextImpl appContext = new ContextImpl();
appContext.init(packageInfo,null,this); ... appContext.setOuterContext(service);

Service對應的Context對象內部的mPackageInfo與Activity、Application中是徹底相同的。

這幾個Context之間的關係

從以上能夠看出,建立Context對象的過程基本上是相同的,不一樣的僅僅是針對Application、Activity、Service使用了不一樣的數據對象。

一個應用程序包含的Context個數應該爲:Context個數 = Service個數+Activity個數+1,最後的1是Application類自己也會對應一個Context對象。

應用程序中包含多個ContextImpl對象,而內部變量mPackageInfo卻指向同一個PackageInfo對象,這種設計結構通常意味着ContextImpl是一種輕量級類,而PackageInfo是一個重量級類。事實上確實是這樣,ContextImpl中的大多數進行包操做的重量級函數實際上都是轉向了mPackageInfo對象相應的方法,也就是事實上調用了同一個PackageInfo對象。

相關文章
相關標籤/搜索