Activity、Service和Application的Context的區別

1、Context的類圖

在這裏插入圖片描述

  • Context:是一個接口類,主要提供通用接口

  • ContextImpl:Context接口的具體實現類

  • ContextWrapper:Context的包裝類,內部持有一個ContextImpl的實例對象mBase,對Context的操作最終都進入ContextImpl類

  • ContextThemeWrapper:該類內部包含了主題(Theme)相關的接口,即android:theme屬性指定的。Service不需要主題,所以Service直接繼承於ContextWrapper類。而Activity繼承此類。

個應用包含的Context個數:Service個數+Activity個數+1(Application類本身對應一個Context對象)。

2、Context的類型

並不是所有的context實例都是等價的。根據Android應用的組件不同,訪問的context推向有些細微的差別。

  • Application - 是一個運行在你的應用進程中的單例。在Activity或者Service中,它可以通過getApplication()函數獲得,或者人和繼承於context的對象中,通過getApplicationContext()方法獲得。不管你是通過何種方法在哪裏獲得的,在一個進程內,你總是獲得到同一個實例。

  • Activity/Service - 繼承於ContextWrapper,它實現了與context同樣API,但是代理這些方法調用到內部隱藏的Context實例,即我們所知道的基礎context。任何時候當系統創建一個新的Activity或者Service實例的時候,它也創建一個新的ContextImpl實例來做所有的繁重的工作。每一個Activity和Service以及其對應的基礎context,對每個實例來說都是唯一的。

  • BroadcastReciver - 它本身不是context,也沒有context在它裏面,但是每當一個新的廣播到達的時候,框架都傳遞一個context對象到onReceive()。這個context是一個ReceiverRestrictedContext實例,它有兩個主要函數被禁掉:registerReceiver()和bindService()。這兩個函數在BroadcastReceiver.onReceive()不允許調用。每次Receiver處理一個廣播,傳遞進來的context都是一個新的實例。

  • ContentProvider - 它本身也不是一個Context,但是它可以通過getContext()函數給你一個Context對象。如果ContentProvider是在調用者的的本地(例如,在同一個應用進程),getContext()將返回的是Application單例。然而,如果調用這和ContentProvider在不同的進程的時候,它將返回一個新創建的實例代表這個Provider所運行的包。

3、不同Context的能力

在這裏插入圖片描述

注:NO1 表示Application context的確可以開始一個Activity,但是它需要創建一個新的task。這可能會滿足一些特定的需求,但是在你的應用中會創建一個不標準的回退棧(back stack),這通常是不推薦的或者不是是好的實踐。

NO2 表示這是非法的,但是這個填充(inflation)的確可以完成,但是是使用所運行的系統默認的主題(theme),而不是你app定義的主題。

NO3 在Android4.2以上,如果Receiver是null的話(這是用來獲取一個sticky broadcast的當前 值的),這是允許的。

4、與UI相關的都用Activity

從前面的表格中可以看到,application context有很多功能並不是合適去做,而這些功能都與UI相關。實際上,只有Activity能夠處理所有與UI相關的任務。其他類別的context實例功能都差不多。

嘗試顯示一個使用Aplication context創建的Dialog,或者使用Application context開始一個Activity,系統會拋出一個異常,讓你的application崩潰,非常強的告訴你某些地方出了問題。

填充View(inflating layout)和使用的Context有很大關係。當你使用Application context來inflate一個佈局的時候,框架並不會報錯,並返回一個使用系統默認的主題創建一個完美的view給你,而沒有考慮你的applicaiton自定義的theme和style。這是因爲Acitivity是唯一的綁定了在manifast文件種定義主題的Context。其他的Context實例將會使用系統默認的主題來inflater你的view。導致顯示的結果並不是你所希望的。可以參考博客 http://www.doubleencore.com/2013/05/layout-inflation-as-intended/

5、 使用Context的小經驗

1、可能有些情況下,在某些Application的設計中,我們可能既必須長期保存一個的引用,並且爲了完成與UI相關的工作又必須保存一個Activity。如果出現這種情況,我將會強烈建議你重新考慮你的設計,它將是一個很好的“反框架”教材。

2、絕大多數情況下,使用在你的所工作的組建內部能夠直接獲取的Context。只要這個引用沒有超過這個組建的生命週期,你可以安全的保存這個引用。一旦你要保存一個context的引用,它超過了你的Activity或者Service的生命週期範圍,甚至是暫時的,你就需要轉換你的引用爲Application context。

6、一個APP中有多少個Context

通常等於 Application + Activity + Service 的數量,而Application通常爲1,因爲應用通常是單進程。

7、Activity、Service、Applciation的對比總結

Activity

  • 1、UI相關的Context都推薦使用Activity,否則有可能會有異常
  • 2、Activity的功能最全面,可以在任何需要Context的地方使用Activity

Service

  • 1、不能用來創建Dialog
  • 2、如果用來進行視圖填充(LayoutInflation),設置的主題不會生效,只會顯示默認主題
  • 3、如果用來啓動一個Activity,新的Activity會在一個新的task任務棧,不建議這麼使用

Applciation

  • 1、直接用來創建創建Dialog,會拋異常Crash,除非進行特殊設置,所以不建議這麼使用
  • 2、和Service相同,不建議用來進行視圖填充(LayoutInflation),否則只顯示默認主題
  • 3、和Service相同,不建議用來啓動Activity
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章