Android Context 上下文 你必須知道的一切

一、Context概念

其實一直想寫一篇關於Context的文章,可是又怕技術不如而誤人子弟,因而參考了些資料,今天準備整理下寫出來,若有不足,請指出,參考資料會在醒目地方標明。java

Context,相信不論是第一天開發Android,仍是開發Android的各類老鳥,對於Context的使用必定不陌生~~你在加載資源、啓動一個新的Activity、獲取系統服務、獲取內部文件(夾)路徑、建立View操做時等都須要Context的參與,可見Context的常見性。你們可能會問到底什麼是Context,Context字面意思上下文,或者叫作場景,也就是用戶與操做系統操做的一個過程,好比你打電話,場景包括電話程序對應的界面,以及隱藏在背後的數據;android

可是在程序的角度Context又是什麼呢?在程序的角度,咱們能夠有比較權威的答案,Context是個抽象類,咱們能夠直接經過看其類結構來講明答案:app

能夠看到Activity、Service、Application都是Context的子類;ide

也就是說,Android系統的角度來理解:Context是一個場景,表明與操做系統的交互的一種過程。從程序的角度上來理解:Context是個抽象類,而Activity、Service、Application等都是該類的一個實現。工具

 

在仔細看一下上圖:Activity、Service、Application都是繼承自ContextWrapper,而ContextWrapper內部會包含一個base context,由這個base context去實現了絕大多數的方法。this

先扯這麼多,有能力了會從別的角度去審視Context,加油~spa

 

二、Context與ApplicationContext

看了標題,千萬不要被誤解,ApplicationContext並無這個類,其實更應該叫作:Activity與Application在做爲Context時的區別。嗯,的確是這樣的,你們在須要Context的時候,若是是在Activity中,大多直接傳個this,當在匿名內部類的時候,由於this不能用,須要寫XXXActivity.this,不少哥們會偷懶,直接就來個getApplicationContext。那麼你們有沒有想過,XXXActivity.this和getApplicationContext的區別呢?操作系統

XXXActivity和getApplicationContext返回的確定不是一個對象,一個是當前Activity的實例,一個是項目的Application的實例。既然區別這麼明顯,那麼各自的使用場景確定不一樣,亂使用可能會帶來一些問題。code

下面開始介紹在使用Context時,須要注意的問題。對象

 

三、引用的保持

你們在編寫一些類時,例如工具類,可能會編寫成單例的方式,這些工具類大多須要去訪問資源,也就說須要Context的參與。

在這樣的狀況下,就須要注意Context的引用問題。

例如如下的寫法:

 

 
package com.mooc.shader.roundimageview;
 
import android.content.Context;
 
public class CustomManager
 
{
 
private static CustomManager sInstance;
 
private Context mContext;
private CustomManager(Context context)
{
this.mContext = context;
}
public static synchronized CustomManager getInstance(Context context)
{
if (sInstance == null)
{
sInstance = new CustomManager(context);
}
return sInstance;
}
//some methods
private void someOtherMethodNeedContext()
{
}
}


對於上述的單例,你們應該都不陌生(請別計較getInstance的效率問題),內部保持了一個Context的引用;

 

這麼寫是沒有問題的,問題在於,這個Context哪來的咱們不能肯定,很大的可能性,你在某個Activity裏面爲了方便,直接傳了個this;這樣問題就來了,咱們的這個類中的sInstance是一個static且強引用的,在其內部引用了一個Activity做爲Context,也就是說,咱們的這個Activity只要咱們的項目活着,就沒有辦法進行內存回收。而咱們的Activity的生命週期確定沒這麼長,因此形成了內存泄漏。

那麼,咱們如何才能避免這樣的問題呢?

有人會說,咱們能夠軟引用,嗯,軟引用,假如被回收了,你不怕NullPointException麼。

把上述代碼作下修改:

 

 
public static synchronized CustomManager getInstance(Context context)
{
if (sInstance == null)
{
sInstance = new CustomManager(context.getApplicationContext());
}
return sInstance;
}這樣,咱們就解決了內存泄漏的問題,由於咱們引用的是一個ApplicationContext,它的生命週期和咱們的單例對象一致。

這樣的話,可能有人會說,早說嘛,那咱們之後都這麼用不就好了,很遺憾的說,不行。上面咱們已經說過,Context和Application Context的區別是很大的,也就是說,他們的應用場景(你也能夠認爲是能力)是不一樣的,並不是全部Activity爲Context的場景,Application Context都能搞定。

下面就開始介紹各類Context的應用場景。

四、Context的應用場景

 

你們注意看到有一些NO上添加了一些數字,其實這些從能力上來講是YES,可是爲何說是NO呢?下面一個一個解釋:

數字1:啓動Activity在這些類中是能夠的,可是須要建立一個新的task。通常狀況不推薦。

數字2:在這些類中去layout inflate是合法的,可是會使用系統默認的主題樣式,若是你自定義了某些樣式可能不會被使用。

數字3:在receiver爲null時容許,在4.2或以上的版本中,用於獲取黏性廣播的當前值。(能夠無視)

注:ContentProvider、BroadcastReceiver之因此在上述表格中,是由於在其內部方法中都有一個context用於使用。

 

好了,這裏咱們看下錶格,重點看Activity和Application,能夠看到,和UI相關的方法基本都不建議或者不可以使用Application,而且,前三個操做基本不可能在Application中出現。實際上,只要把握住一點,凡是跟UI相關的,都應該使用Activity作爲Context來處理;其餘的一些操做,Service,Activity,Application等實例均可以,固然了,注意Context引用的持有,防止內存泄漏。

 

五、總結

好了,到此,Context的分析基本完成了,但願你們在之後的使用過程當中,可以稍微考慮下,這裏使用Activity合適嗎?會不會形成內存泄漏?這裏傳入Application work嗎?

因爲參考內容過多,本文改成譯文咯~~

相關文章
相關標籤/搜索