原文鏈接:https://blog.csdn.net/LoveFHM/article/details/139291276
一、什么是Context?
Context是一個(gè)抽象基類。在翻譯為上下文,是提供一些程序的運(yùn)行環(huán)境基礎(chǔ)信息。
如下圖:Context下有兩個(gè)子類,ContextWrapper是上下文功能的封裝類(起到方法傳遞的作用,主要實(shí)現(xiàn)還是ContextImpl),而ContextImpl則是上下文功能的實(shí)現(xiàn)類。
- 如下圖:ContextWrapper又有三個(gè)直接的子類,ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一個(gè)帶主題的封裝類,所說的主題就是指在AndroidManifest.xml中通過android:theme為Application元素或者Activity元素指定的主題,而它有一個(gè)直接子類就是Activity,所以Activity和Service以及Application的Context是不一樣的,只有Activity需要主題,Service不需要主題。
- 其中最核心的類就是ContextImpl類。ContextImpl類繼承了抽象類Context并且實(shí)現(xiàn)所有的抽象方法,并且自身還實(shí)現(xiàn)了很多get,create,check開頭的方法。
- 一個(gè)應(yīng)用程序進(jìn)程中有多少個(gè) Context ,這個(gè)數(shù)量等于 Activity 和 Service 的總個(gè)數(shù)加 1,1指的是 Application 的數(shù)量。

二、Context的子類及其作用
Context一共有三種類型,分別是Application、Activity和Service。
這三個(gè)類雖然分別各種承擔(dān)著不同的作用,但它們都屬于Context的一種,而它們具體Context的功能則是由ContextImpl類去實(shí)現(xiàn)的,因此在絕大多數(shù)場(chǎng)景下,Activity、Service和Application這三種類型的Context都是可以通用的。
在我們的實(shí)際開發(fā)中,context會(huì)被大量的使用到,例如startActivity,訪問資源,toast彈出,dialog,啟動(dòng)service,發(fā)送廣播等等。
不過有幾種場(chǎng)景要特別注意,
比如啟動(dòng)Activity,還有彈出Dialog。出于安全原因的考慮,Android是不允許Activity或Dialog憑空出現(xiàn)的,一個(gè)Activity的啟動(dòng)必須要建立在另一個(gè)Activity的基礎(chǔ)之上,也就是以此形成的返回棧。而Dialog則必須在一個(gè)Activity上面彈出(除非是系統(tǒng)級(jí)別吐司),因此在這種場(chǎng)景下,我們只能使用Activity類型的Context,否則將會(huì)出錯(cuò)。
再比如我們用ApplicationContext去啟動(dòng)一個(gè)LaunchMode為standard的Activity的時(shí)候會(huì)報(bào)錯(cuò),因?yàn)檫@時(shí)候的ApplicationContext,它沒有任務(wù)棧啊,解決這個(gè)問題的方法就是為待啟動(dòng)的Activity指定FLAG_ACTIVITY_NEW_TASK標(biāo)記位,這樣啟動(dòng)的時(shí)候就為它創(chuàng)建一個(gè)新的任務(wù)棧。
三、Context的獲取
-
View.getContext,返回當(dāng)前View對(duì)象的Context對(duì)象,通常是當(dāng)前正在展示的Activity對(duì)象。
例如我們?cè)赼dapter里面
image.png - Activity.getApplicationContext,獲取當(dāng)前Activity所在的(應(yīng)用)進(jìn)程的Context對(duì)象,通常我們使用Context對(duì)象時(shí),要優(yōu)先考慮這個(gè)全局的進(jìn)程Context。
getApplication和getApplicationContext的區(qū)別。如果你在Activity里面打印這個(gè)兩個(gè)方法的話,得到對(duì)象內(nèi)存地址是一樣的,也就是這兩個(gè)方法獲取的對(duì)象是一樣的?實(shí)際上,這兩個(gè)獲取到的對(duì)象就是同一個(gè)對(duì)象,Application本身就是一個(gè)Context,所以這里獲取getApplicationContext()得到的結(jié)果就是Application本身的實(shí)例。他們只是可以使用的范圍是不一樣的
getApplication這個(gè)方法一看就知道是用來獲取Application實(shí)例的,只有Activity和Service才有,要想在別的地方獲取Application就只能通過getApplicationContext獲?。ɡ鐝V播)。

- ContextWrapper.getBaseContext():用來獲取一個(gè)ContextWrapper進(jìn)行裝飾之前的Context(用得少,不介紹)
四、Context內(nèi)存泄漏
這個(gè)context的內(nèi)存泄漏在app開發(fā)中隨處可見,一個(gè)activity本來應(yīng)該被回收了,但是因?yàn)閮?nèi)部類啊,或者有些靜態(tài)方法的引用導(dǎo)致無法被回收。
所以說,我們應(yīng)當(dāng)
- 當(dāng)Application的Context能搞定的情況下,并且生命周期長(zhǎng)的對(duì)象,優(yōu)先使用Application的Context。
- 不要讓生命周期長(zhǎng)于Activity的對(duì)象持有到Activity的引用。
- 盡量不要在Activity中使用非靜態(tài)內(nèi)部類,因?yàn)榉庆o態(tài)內(nèi)部類會(huì)隱式持有外部類實(shí)例的引用,如果使用靜態(tài)內(nèi)部類,將外部實(shí)例引用作為弱引用持有。
五、Context的創(chuàng)建源碼分析
application,activity和service的創(chuàng)建流程,其實(shí)都是通過反射后創(chuàng)建application,activity和service對(duì)象的同時(shí)創(chuàng)建了一個(gè)ContextImpl對(duì)象,并與之關(guān)聯(lián)。
簡(jiǎn)要流程:
- application
- ActivityThread.main方法--> ActivityManagerService.bindApplication方法 --> ActivityThread.handleBindApplication --> 創(chuàng)建Instrumentation,創(chuàng)建Application;
- 每個(gè)應(yīng)用進(jìn)程對(duì)應(yīng)一個(gè)Instrumentation,對(duì)應(yīng)一個(gè)Application;
- Instrumentation與Application都是通過java反射機(jī)制創(chuàng)建;
- Application 創(chuàng)建過程中會(huì)同時(shí)創(chuàng)建一個(gè) ContextImpl 對(duì)象,并建立關(guān)聯(lián);
- acticity
- Activity中創(chuàng)建ContextImpl對(duì)象的具體實(shí)現(xiàn)在ActivityThread的performLauncherActivity方法中;
- Activity的創(chuàng)建伴隨著ContextImpl的創(chuàng)建,二者相互持有對(duì)方的引用;
- service
- ActivityThread的main方法走到thread.attach(false);
- 調(diào)用mgr.attachApplication(mAppThread);方法,熟悉吧
- 實(shí)際上調(diào)用ActivityManagerService的attachApplication(),再調(diào)用attachApplicationLocked方法,這里面創(chuàng)建application,activity和service
- 關(guān)于service,他會(huì)走到 didSomething |= mServices.attachApplicationLocked(app, processName);執(zhí)行service的后續(xù)操作,mServices是ActiveServices,走到attachApplicationLocked方法里,
- 調(diào)用app.thread.scheduleCreateService(),這不就來了。
- ActivityThread里的scheduleCreateService通過- sendMessage(H.CREATE_SERVICE, s);發(fā)送創(chuàng)建Service的消息
- 在handler的handleMessage里走到handleCreateService()
核心代碼:
private void handleCreateService(CreateServiceData data) {
Service service = null;
try {
//(1)通過類加載器來加載 Service 對(duì)象
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
//......
}
//(2)這里創(chuàng)建 ContextImpl 對(duì)象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,ActivityManagerNative.getDefault());
//(3)這里調(diào)用 Service 的 onCreate 方法
service.onCreate();
mServices.put(data.token, service);
}
