目录
前言
对于Application,Activity和Service这几个类,我们是很[熟悉]的。确实[熟悉],作为App开发这基本都要面对这几个类。
比较好奇的朋友会发现,他们都拥有Context,但他们的Context有似乎有一点点的不同。今天有空,根据网上大佬的步伐,在这里简单记录一下。
正文
Context的使用场景
使用Context调用方法,比如启动Activity、访问资源、调用系统级服务等。
调用方法时传入Context,比如弹出Toast、创建Dialog等。
Context意为[上下文],也是Application,Activity和ServiceContext的祖先类。
Application -> ContextWrapper -> Context; Activity -> ContextThemeWrapper -> ContextWrapper -> Context Service -> ContextWrapper -> Context
或者看图,图上更详细
通过源码发现,Context其实也不干活的,具体干活的是ContextImpl。
今天就介绍一下Application的Context。
Application的Context
在Application中,经常通过如下获取Context
Context context = getApplicationContext();
getApplicationContext()是ContextWrapper中的类
ContextWrapper.java
@Override public Context getApplicationContext() { return mBase.getApplicationContext(); }
竟然调用的是mBase的
Context mBase;
Context.java
public abstract Context getApplicationContext();
啊哈,竟然是抽象方法。那就找它的儿子类们。
从上面继承图中看到Context的儿子类有ContextWrapper和ContextImpl,我们是从ContextWrapper中跟入的,没有实现,那就是ContextImpl进行了实现。
ContextImpl.java
@Override public Context getApplicationContext() { return (mPackageInfo != null) ? mPackageInfo.getApplication() : mMainThread.getApplication(); }
从上面看的话,如果mPackageInfo不为null,就通过mPackageInfo的方法总获取,否则就通过mMainThread的方法中获取。
final @NonNull LoadedApk mPackageInfo; final @NonNull ActivityThread mMainThread;
我们分别看看mPackageInfo和mMainThread初始化。
ContextImpl()
private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread, @NonNull LoadedApk packageInfo, @Nullable String splitName, @Nullable IBinder activityToken, @Nullable UserHandle user, int flags, @Nullable ClassLoader classLoader) { //略 //mMainThread赋值 mMainThread = mainThread; //略 //mPackageInfo赋值 mPackageInfo = packageInfo; //略 }
从上面看,mPackageInfo和mMainThread赋值都在这里,但调用new ContextImpl()方法确实很多,都在ContextImpl.java中。
1. createAppContext(); 2. createActivityContext(); 3. createSystemUiContext(); 4. createSystemContext(); 等
根据参考文和我们之前的源码分析《》,知道ActivityThread.java中会去创建Application。
ActivityThread.java
Application的创建是在H发送BIND_APPLICATION中进行创建的。
handleMessage()
public void handleMessage(Message msg) { switch (msg.what) { case BIND_APPLICATION: AppBindData data = (AppBindData)msg.obj; //处理和绑定 handleBindApplication(data); break; //略 } }
handleBindApplication()
private void handleBindApplication(AppBindData data) { //略,[大部分不关注的略了] Application app; try { //[重]创建Application app = data.info.makeApplication(data.restrictedBackupMode, null); //略 try { //调用mInstrumentation的onCreate() mInstrumentation.onCreate(data.instrumentationArgs); }catch (Exception e) { } try { //执行Application的onCreate()方法 mInstrumentation.callApplicationOnCreate(app); } catch (Exception e) { } } finally { if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1 || StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) { StrictMode.setThreadPolicy(savedPolicy); } } //略 }
这里我们只关注Application的创建,也就是
app = data.info.makeApplication(data.restrictedBackupMode, null);
这里的data.info就是LoadedApk对象。
LoadedApk.java
makeApplication()
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) { //第一次执行,这里为null,但再次进入这里就不会null啦 if (mApplication != null) { return mApplication; } Application app = null; //启动应用的Application包名 String appClass = mApplicationInfo.className; if (forceDefaultAppClass || (appClass == null)) { //如果为null,就赋值默认的 appClass = "android.app.Application"; } try { java.lang.ClassLoader cl = getClassLoader(); //略 //[重]创建appContext ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); //[重]创建Application app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); appContext.setOuterContext(app); } catch ( e) { //略 } //赋值给mApplication mApplication = app; //略 return app; }
先看appContext的创建
ContextImpl.java
createAppContext()
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { //packageInfo不为null if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); //创建了Application的context //也就是回到我们上面介绍的了,packageInfo不为null ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, null); context.setResources(packageInfo.getResources()); return context; }
至此,Application的Context已经创建了。
再看看Application的创建,既然创建了Application的Context,那需要跟Application进行绑定。
回到上面
//创建Application app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext);
调用的是Instrumentation的newApplication()方法
Instrumentation.java
newApplication()
public Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException { //getPackageName()包名:com.biumall.image //className类名:com.biumall.image.ImageApp //具体看了一下,instantiateApplication()实现方式 //实例化了一个Application Application app = getFactory(context.getPackageName()) .instantiateApplication(cl, className); //[重]绑定了Application Context app.attach(context); return app; }
Application.java
attach()
final void attach(Context context) { //绑定到mBase中 attachBaseContext(context); //赋值mLoadedApk mLoadedApk = ContextImpl.getImpl(context).mPackageInfo; }
ContextWrapper.java
protected void attachBaseContext(Context base) { //只能设置一次 if (mBase != null) { throw new IllegalStateException("Base context already set"); } mBase = base; }
mBase就是Application Context。
回到ContextImpl.java中,也就是上面的getApplicationContext()获取处。
ContextImpl.java
getApplicationContext()
@Override public Context getApplicationContext() { return (mPackageInfo != null) ? mPackageInfo.getApplication() : mMainThread.getApplication(); }
中的mPackageInfo就是上面赋值的LoadedApk对象,不为null
# LoadedApk对象 mPackageInfo.getApplication()
LoadedApk.java
进入getApplication()
getApplication()
Application getApplication() { return mApplication; }
这里返回的mApplication就是在makeApplication()中创建的Application。
参考文章
《》
《Android进阶解密-刘望舒》
《Android内核剖析-柯元旦》