版權(quán)聲明:本文為博主原創(chuàng)文章逼蒙,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議澈蝙,轉(zhuǎn)載請(qǐng)附上原文出處鏈接和本聲明吓坚。
本文鏈接:http://www.reibang.com/p/674682b1976f
背景:我們經(jīng)常在Activity中會(huì)得到一些系統(tǒng)服務(wù)或者得到Resources,比如ACTIVITY_SERVICE灯荧,常常獲取的方式有好幾種礁击,如下:
//得到ACTIVITY_SERVICE
getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
this.getSystemService(Context.ACTIVITY_SERVICE);
getBaseContext().getSystemService(Context.ACTIVITY_SERVICE);
//得到Resources
getResources();
getBaseContext().getResources();
getApplicationContext().getResources();
這時(shí)候就有一種疑問(wèn),最后返回的是同一個(gè)對(duì)象嗎,如果不是哆窿,又會(huì)有什么差異链烈。
要想弄清上面的問(wèn)題,先得明白Context更耻,ContextImpl测垛,ContextWrapper捏膨,ContextThemeWrapper秧均,Activity,Application等等的關(guān)系号涯。
public abstract class Context {
public abstract Resources getResources();
public abstract Object getSystemService(@ServiceName @NonNull String name);
}
class ContextImpl extends Context {
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
@Override
public Resources getResources() {
return mResources;
}
}
public class ContextWrapper extends Context {
Context mBase;
@Override
public Resources getResources() {
return mBase.getResources();
}
@Override
public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
}
public class ContextThemeWrapper extends ContextWrapper {
@Override
public Object getSystemService(String name) {
if (LAYOUT_INFLATER_SERVICE.equals(name)) {
if (mInflater == null) {
mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
}
return mInflater;
}
return getBaseContext().getSystemService(name);
}
}
public class Activity extends ContextThemeWrapper{
}
從上面的代碼可以知道目胡,Context是一個(gè)抽象類(lèi),它的很多方法链快,比如getResources誉己,getSystemService等都是抽象方法。ContextWrapper類(lèi)和ContextImpl類(lèi)都繼承了Context域蜗,但是他們的實(shí)現(xiàn)方法不一樣巨双。ContextWrapper中主要是調(diào)用mBase對(duì)應(yīng)的方法,而mBase也是一個(gè)Context對(duì)象霉祸。
其實(shí)通過(guò)研讀ActivityThread的performLaunchActivity(參考http://www.reibang.com/p/76f94c6452c0)我們不難明白筑累,Activity中對(duì)應(yīng)的Context實(shí)例對(duì)象是其實(shí)都是ContextImpl對(duì)象,ContextImpl也是真正實(shí)現(xiàn)Context的唯一對(duì)象丝蹭。且ContextWrapper中的mBase對(duì)象實(shí)際上也是ContextImpl慢宗。ContextWrapper顧名思義,它只是Context的一個(gè)包裹奔穿,最終調(diào)用到的也是ContextImpl中的實(shí)現(xiàn)镜沽。而Activity也繼承了ContextWrapper,所以最后殊途同歸贱田,所有的調(diào)用最終調(diào)用到了ContextImpl中缅茉。
那Application又合Context有什么關(guān)系呢,如下:
public class Application extends ContextWrapper{
}
可以看到Application也繼承ContextWrapper男摧,ContextWrapper繼承Context蔬墩,所以通過(guò)調(diào)用getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);最終調(diào)用到的是Application中的mBase的對(duì)應(yīng)的getSystemService方法,mBase它是Context對(duì)象彩倚,也是ContextImpl實(shí)例筹我,那它是如何設(shè)置為ContextImpl實(shí)例的呢,Application中有一attach函數(shù)帆离,參數(shù)為context蔬蕊,它的調(diào)用是LoadedApk中的makeApplication時(shí)調(diào)用的
final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
Application app = null;
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
}
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return newApplication(cl.loadClass(className), context);
}
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
所以可以看到Application中最終也是調(diào)用到了ContextImpl中去。
至此,我們明白了getSystemService岸夯,無(wú)論是Activity的直接getSystemService()調(diào)用麻献,還是通過(guò)getBaseContext調(diào)用還是getApplicationContext()調(diào)用,最終都是調(diào)用到了ContextImpl中去猜扮。我們來(lái)看看具體的代碼跟蹤勉吻。
getSystemService代碼跟蹤,Activity中有WINDOW_SERVICE和SEARCH_SERVICE的緩存旅赢,直接返回
@Override
public Object getSystemService(@ServiceName @NonNull String name) {
if (getBaseContext() == null) {
throw new IllegalStateException(
"System services not available to Activities before onCreate()");
}
if (WINDOW_SERVICE.equals(name)) {
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager();
return mSearchManager;
}
return super.getSystemService(name);
}
//super.getSystemService(name)
@Override
public Object getSystemService(String name) {
if (LAYOUT_INFLATER_SERVICE.equals(name)) {
if (mInflater == null) {
mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
}
return mInflater;
}
return getBaseContext().getSystemService(name);
}
可以看到最后是調(diào)用到了getBaseContext()的getSystemService齿桃,getBaseContext返回的是mBase對(duì)象,mBase對(duì)象是ContextImpl(Context)對(duì)象煮盼。它是在Activity的attach的時(shí)候設(shè)置的(參考http://www.reibang.com/p/76f94c6452c0)
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaseContext(context);
}
所以最終調(diào)用到了ContextImpl的getSystemService短纵。
在看ContextImpl的getSystemService之前,先來(lái)看看通過(guò)Application的調(diào)用
//Activity中
getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
@Override
public Context getApplicationContext() {
return mBase.getApplicationContext();
}
我們知道Activity中的mBase是ContextImpl對(duì)象僵控,那么它的getApplicationContext返回什么對(duì)象呢
final LoadedApk mPackageInfo;
@Override
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
mPackageInfo是一個(gè)LoadedApk對(duì)象香到,它返回的mApplication對(duì)象就是調(diào)用makeApplication生成的Application對(duì)象。(見(jiàn)上面講解代碼)
private Application mApplication;
Application getApplication() {
return mApplication;
}
即也就是調(diào)用到了Application中的getSystemService报破。而Application繼承ContextWrapper悠就,所以又是調(diào)用到了mBase的getSystemService。mBase為ContextImpl對(duì)象充易,所以最終調(diào)用到了ContextImpl中去梗脾。
下面我們來(lái)看看最終ContextImpl的調(diào)用
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
//SystemServiceRegistry中的getSystemService
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
最終就是調(diào)用到了SystemServiceRegistry中注冊(cè)的系統(tǒng)服務(wù)了。具體可以參考SystemServiceRegistry的源代碼蔽氨。這個(gè)就是屬于注冊(cè)系統(tǒng)服務(wù)的范疇了藐唠。非本篇討論范圍。
最后是不是會(huì)有一個(gè)疑問(wèn)鹉究,一個(gè)應(yīng)用中到底會(huì)有多少個(gè)ContextImpl對(duì)象實(shí)例宇立,一個(gè)還是多個(gè)。如果是多個(gè)對(duì)象自赔,如何保證調(diào)用的最后歸一呢妈嘹。多個(gè)對(duì)象豈不是會(huì)占用很多內(nèi)存。
說(shuō)到這些绍妨,就不得不提ContextImpl中比較重要的兩個(gè)成員變量了
final ActivityThread mMainThread;
final LoadedApk mPackageInfo;
同時(shí)润脸,我們看到ContextImpl中有很多創(chuàng)建Context相關(guān)的函數(shù),比如
static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
ContextImpl context = new ContextImpl(null, mainThread,
packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetrics());
return context;
}
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread,
packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
}
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0,
null, overrideConfiguration, displayId);
}
@Override
public Context createApplicationContext(ApplicationInfo application, int flags)
throws NameNotFoundException {
LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE);
if (pi != null) {
ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
new UserHandle(UserHandle.getUserId(application.uid)), flags,
mDisplay, null, Display.INVALID_DISPLAY);
if (c.mResources != null) {
return c;
}
}
throw new PackageManager.NameNotFoundException(
"Application package " + application.packageName + " not found");
}
@Override
public Context createPackageContext(String packageName, int flags)
throws NameNotFoundException {
return createPackageContextAsUser(packageName, flags,
mUser != null ? mUser : Process.myUserHandle());
}
@Override
public Context createConfigurationContext(Configuration overrideConfiguration) {
if (overrideConfiguration == null) {
throw new IllegalArgumentException("overrideConfiguration must not be null");
}
return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
mUser, mFlags, mDisplay, overrideConfiguration, Display.INVALID_DISPLAY);
}
``
可以看到ContextImpl是會(huì)創(chuàng)建很多次的他去,它是一個(gè)輕量級(jí)的對(duì)象毙驯,雖然ContextImpl會(huì)被創(chuàng)建多個(gè),但是它的成員變量mMainThread和mPackageInfo的對(duì)象引用是唯一的灾测。這也是一個(gè)android進(jìn)程里面比較重要的兩個(gè)類(lèi)爆价。也只會(huì)生成唯一的對(duì)象。從中我們也可以看到google工程師設(shè)計(jì)android框架的一些巧妙之處和原理,希望能從中學(xué)習(xí)一二铭段。