1.Context基本概念
Context的中文翻譯為:語境; 上下文; 背景; 環(huán)境厅瞎,在開發(fā)中我們經(jīng)常說稱之為“上下文”。從Android系統(tǒng)的角度來理解:Context是一個場景荔泳,代表與操作系統(tǒng)的交互的一種過程。Context在加載資源、啟動Activity、獲取系統(tǒng)服務(wù)晌区、創(chuàng)建View等操作都要參與 。從程序的角度上來理解:Context是個抽象類通贞,而Activity朗若、Service、Application等都是該類的一個實現(xiàn)滑频。
2.Context與Activity、Service唤冈、Application關(guān)系
Context類本身是一個純abstract類峡迷,他有兩個具體的實現(xiàn)子類:ContextImpl和ContextWrapper。其中ContextWrapper類你虹,只是一個包裝而已绘搞,ContextWrapper構(gòu)造函數(shù)中必須包含一個真正的Context引用,同時ContextWrapper提供了attachBaseContext()用于給ContextWrapper對象中指定真正的Context對象傅物,調(diào)用ContextWrapper的方法都會被轉(zhuǎn)向其所包含的真正的Context對象夯辖。ContextThemeWrapper類,其內(nèi)部包含了與主題(Theme)相關(guān)的接口董饰,這里所說的主題就是指在AndroidMainifest.xml中通過android:theme為Application元素或者Activity元素指定的主題蒿褂。當然圆米,只有Activity才需要主題,Service是不需要主題的啄栓,Application同理娄帖。而ContextImpl類則真正實現(xiàn)了Context中的所有函數(shù),應(yīng)用程序中所調(diào)用的各種Context類的方法昙楚,其實現(xiàn)均來于該類近速。Context的兩個子類分工明確,其中ContextImpl是Context的具體實現(xiàn)類堪旧,ContextWrapper是Context的包裝類削葱。
3.Context作用域
Activity的作用域最廣,Application和Service在啟動Activity需要創(chuàng)建一個新的task淳梦,一般不推薦析砸。layout infalte也是合法的,但是會使用系統(tǒng)默認的主題樣式谭跨,如果自定義某些樣式可能不會被使用
4.Context的使用
4.1Context的數(shù)量
一個應(yīng)用程序中到底有多少個Context呢干厚?根據(jù)Context的類型可以得出,一共有Application螃宙、Activity和Service三種類型蛮瞄,因此一個應(yīng)用程序的Context數(shù)量為:Context數(shù)量=Activity數(shù)量+Service數(shù)量+1
4.2如何獲取Context
1)View.getContext,返回當前Activity所在的應(yīng)用進程的Context對象,通常是當前正在展示的Activity對象2)Activity.getApplicationContext,獲取當前Activity所在的(應(yīng)用)進程的Context對象谆扎,通常我們使用Context對象時挂捅,要優(yōu)先考慮這個全局的進程Context。3)Activity.this返回當前的Activity實例堂湖,如果是UI控件需要使用Activity作為Context對象闲先,但是默認的Toast因為是系統(tǒng)層級的Windows,直接使用ApplicationContext則可无蜂。4)getApplication和getApplicationContext獲取的對象時一致的伺糠。但是getApplication方法只有在Activity和Service中才能調(diào)到。但例如BroadcasrReceiver中需要獲取Application斥季,則需要借助getApplicationContext()方法训桶。
4.3Context引起的內(nèi)測泄漏
1)錯誤的單例模式
public class Singleton {
private static Singleton instance;
private Context mContext;
private Singleton(Context context) {
this.mContext = context;
}
public static Singleton getInstance(Context context) {
if (instance == null) {
instance = new Singleton(context);
}
return instance;
}
}```
即使Activity被銷毀掉,但因為它的引用還存在于一個Singleton中酣倾,就不可能被GC掉
2)View持有Activity引用
public class MainActivity extends Activity {
private static Drawable mDrawable;
@Override
protected void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
ImageView iv = new ImageView(this);
mDrawable = getResources().getDrawable(R.drawable.ic_launcher);
iv.setImageDrawable(mDrawable);
}
}```
有一個靜態(tài)的Drawable對象當ImageView設(shè)置這個Drawable時舵揭,ImageView保存了mDrawable的引用,而ImageView傳入的this是MainActivity的mContext躁锡,因為被static修飾的mDrawable是常駐內(nèi)存的午绳,MainActivity是它的間接引用,MainActivity被銷毀時映之,也不能被GC掉拦焚,所以造成內(nèi)存泄漏蜡坊。
5.總結(jié)
盡量使用Application的Context
不要讓生命周期長于Activity的對象持有其的引用
盡量不要在Activity中使用非靜態(tài)內(nèi)部類,因為非靜態(tài)內(nèi)部類會隱式持有外部類示例的引用耕漱,如果使用靜態(tài)內(nèi)部類算色,將外部實例引用作為弱引用持有