Application的Context介绍

Android 91es.com站长2023年12月6日 am8:08发布6个月前更新
0
导航号,我的单页导航
目录

前言

对于Application,Activity和Service这几个类,我们是很[熟悉]的。确实[熟悉],作为App开发这基本都要面对这几个类。

比较好奇的朋友会发现,他们都拥有Context,但他们的Context有似乎有一点点的不同。今天有空,根据网上大佬的步伐,在这里简单记录一下。

正文

Context的使用场景

  1. 使用Context调用方法,比如启动Activity、访问资源、调用系统级服务等。

  2. 调用方法时传入Context,比如弹出Toast、创建Dialog等。

Context意为[上下文],也是Application,Activity和ServiceContext的祖先类。

Application -> ContextWrapper -> Context;
Activity -> ContextThemeWrapper -> ContextWrapper -> Context
Service -> ContextWrapper -> Context

或者看图,图上更详细

Application的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();
等

根据参考文和我们之前的源码分析startActivity源码分析2-导航号》,知道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。

参考文章

  1. startActivity源码分析2-导航号

  2. 《Android进阶解密-刘望舒》

  3. 《Android内核剖析-柯元旦》

版权声明 1、 本站名称 91易搜
2、 本站网址 https://www.91es.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权请留言
4、 本站禁止发布或转载任何违法的相关信息,如有发现请向站长举报
导航号,我的单页导航

暂无评论

评论审核已启用。您的评论可能需要一段时间后才能被显示。

暂无评论...