今天研究了一下Context類剂桥,對(duì)于context發(fā)現(xiàn)即熟悉又陌生忠烛。一個(gè)我們天天打交道的東西到底是什么呢,這篇文章將帶大家了解context权逗。
簡(jiǎn)介
我們先看google官方的說明
/**
* Interface to global information about an application environment. This is
* an abstract class whose implementation is provided by
* the Android system. It
* allows access to application-specific resources and classes, as well as
* up-calls for application-level operations such as launching activities,
* broadcasting and receiving intents, etc.
*/
public abstract class Context
從上可知一下三點(diǎn),即:
1美尸、它描述的是一個(gè)應(yīng)用程序環(huán)境的信息,即上下文斟薇。
2师坎、該類是一個(gè)抽象(abstract class)類,Android提供了該抽象類的具體實(shí)現(xiàn)類(后面我們會(huì)講到是ContextIml類)堪滨。
3胯陋、通過它我們可以獲取應(yīng)用程序的資源和類,也包括一些應(yīng)用級(jí)別操作,例如:?jiǎn)?dòng)一個(gè)Activity惶岭,發(fā)送廣播寿弱,接受Intent 信息 等。按灶。
那么我們明確第一點(diǎn)症革,context是一個(gè)抽象類,而我們平時(shí)用的context鸯旁,均是其實(shí)現(xiàn)噪矛,而更偉大的是, 我們的application铺罢,我們的activity艇挨,service,均在context的繼承關(guān)系樹的韭赘。
讓我們看一張類圖缩滨,相信看完這個(gè)類圖大家就知道context在我們的應(yīng)用中是什么樣子的地位:
通過看圖,我們知道了泉瞻,一個(gè)應(yīng)用程序App共有的Context數(shù)目公式為:
總Context實(shí)例個(gè)數(shù) = Service個(gè)數(shù) + Activity個(gè)數(shù) + 1(Application對(duì)應(yīng)的Context實(shí)例)
可見脉漏,我們的每個(gè)Activity,Service袖牙,Application都有自己的context侧巨,那么context是什么時(shí)候傳入的呢?
Context的傳入
1.創(chuàng)建Application對(duì)象的時(shí)機(jī)
每個(gè)應(yīng)用程序在第一次啟動(dòng)時(shí),都會(huì)首先創(chuàng)建Application對(duì)象鞭达。在應(yīng)用程序啟動(dòng)Activity(startActivity)流程中司忱,創(chuàng)建Application的時(shí)機(jī)在創(chuàng)建handleBindApplication()方法中,該函數(shù)位于 ActivityThread.java類中 畴蹭,如下:
//創(chuàng)建Application時(shí)同時(shí)創(chuàng)建的ContextIml實(shí)例
private final void handleBindApplication(AppBindData data){
...
///創(chuàng)建Application對(duì)象
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
...
}
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
...
try {
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext = new ContextImpl(); //創(chuàng)建一個(gè)ContextImpl對(duì)象實(shí)例
appContext.init(this, null, mActivityThread); //初始化該ContextIml實(shí)例的相關(guān)屬性
///新建一個(gè)Application對(duì)象
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app); //將該Application實(shí)例傳遞給該ContextImpl實(shí)例
}
...
}
2坦仍、創(chuàng)建Activity對(duì)象的時(shí)機(jī)
通過startActivity()或startActivityForResult()請(qǐng)求啟動(dòng)一個(gè)Activity時(shí),如果系統(tǒng)檢測(cè)需要新建一個(gè)Activity對(duì)象時(shí)叨襟,就會(huì)回調(diào)handleLaunchActivity()方法桨踪,該方法繼而調(diào)用performLaunchActivity()方法,去創(chuàng)建一個(gè)Activity實(shí)例芹啥,并且回調(diào)onCreate(),onStart()方法等铺峭, 函數(shù)都位于 ActivityThread.java類 墓怀,如下:
//創(chuàng)建一個(gè)Activity實(shí)例時(shí)同時(shí)創(chuàng)建ContextIml實(shí)例
private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {
...
Activity a = performLaunchActivity(r, customIntent); //啟動(dòng)一個(gè)Activity
}
private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {
...
Activity activity = null;
try {
//創(chuàng)建一個(gè)Activity對(duì)象實(shí)例
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
}
if (activity != null) {
ContextImpl appContext = new ContextImpl(); //創(chuàng)建一個(gè)Activity實(shí)例
appContext.init(r.packageInfo, r.token, this); //初始化該ContextIml實(shí)例的相關(guān)屬性
appContext.setOuterContext(activity); //將該Activity信息傳遞給該ContextImpl實(shí)例
...
}
...
}
3、創(chuàng)建Service對(duì)象的時(shí)機(jī)
通過startService或者bindService時(shí)卫键,如果系統(tǒng)檢測(cè)到需要新創(chuàng)建一個(gè)Service實(shí)例傀履,就會(huì)回調(diào)handleCreateService()方法,完成相關(guān)數(shù)據(jù)操作。handleCreateService()函數(shù)位于 ActivityThread.java類钓账,如下:
//創(chuàng)建一個(gè)Service實(shí)例時(shí)同時(shí)創(chuàng)建ContextIml實(shí)例
private final void handleCreateService(CreateServiceData data){
...
//創(chuàng)建一個(gè)Service實(shí)例
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
}
...
ContextImpl context = new ContextImpl(); //創(chuàng)建一個(gè)ContextImpl對(duì)象實(shí)例
context.init(packageInfo, null, this); //初始化該ContextIml實(shí)例的相關(guān)屬性
//獲得我們之前創(chuàng)建的Application對(duì)象信息
Application app = packageInfo.makeApplication(false, mInstrumentation);
//將該Service信息傳遞給該ContextImpl實(shí)例
context.setOuterContext(service);
...
}
需要強(qiáng)調(diào)一點(diǎn)的是碴犬,通過對(duì)ContextImp的分析可知,其方法的大多數(shù)操作都是直接調(diào)用其屬性mPackageInfo(該屬性類型為PackageInfo)的相關(guān)方法而來梆暮。這說明ContextImp是一種輕量級(jí)類服协,而PackageInfo才是真正重量級(jí)的類。而一個(gè)App里的所有ContextIml實(shí)例啦粹,都對(duì)應(yīng)同一個(gè)packageInfo對(duì)象
本文作者:Jerey_Jobs
簡(jiǎn)書地址:Anderson大碼渣
github地址:Jerey_Jobs