Context

作者: Drew_MyINTYRE | 来源:发表于2021-10-13 09:12 被阅读0次

    谈谈你对 Android 中 Context 的理解?

    Context 是应用程序和系统之间的桥梁,应用程序访问系统各种资源的接口。

    context. 是从哪里来的?AMS 是系统级进程,拥有访问系统级操作的权利,应用程序的启动受 AMS 的调控,在程序启动的过程中,AMS 会把一个“凭证”通过跨进程通信给到我们的应用程序,我们的程序会把这个“凭证”封装成 context,并提供一系列的接口,这样我们的程序也就可以很方便地访问系统资源了。

    系统可以对应用程序级的操作进行调控,限制各种情景下的权限,同时也可以防止恶意攻击。

    ContextWrapper 继承自 Context,但是并没有真正实现 Context 中的抽象方法,而是把方法的实现都 delegateContextImpl,只需要把ContextImpl 对象赋值进去即可,ContextImplContext 抽象类的真正实现者,从 AMS 拿来的“凭证”也是封装到了ContextImpl 中,然后赋值给 ContextWrapper,这里运用到了一种模式:装饰者模式。运用装饰者模式,向外屏蔽 ContextImpl 的内部逻辑,同时当需要更改 ContextImpl 的逻辑实现,ContextWrapper 的逻辑几乎不需要更改。

    class ContextImpl extends Context { ... }
    
    public abstract class Context { ... }
    
    public class ContextWrapper extends Context { ... }
    
    public class ContextThemeWrapper extends ContextWrapper { ... }
    
    public class Activity extends ContextThemeWrapper { ... }
    

    为什么有 getApplication(), 还要 getApplicationContext()?

    getApplication() 只能在 activity 中调用。而 getApplicationContext() 适用范围更广,任意一个 context 对象都可以调用它。

    自定义 Application 的目的是在程序启动的时候做全局初始化工作,而不能拿来取代工具类,这严重违背谷歌设计 Application 的原则,也违背 Java 代码规范的单一职责原则。

    四大组件里面的 Context 都来源于哪里?

    • Activity 继承自 ContextThemeWrapper ,是一个拥有主题的 context 对象。

    • Service 继承自 ContextWrapper,也可以和 Activity 一样直接使用service.this 来使用 context。和 activity 不同的是,Service 没有界面,所以也不需要主题。

    • ContextProvider 使用的是 Applicationcontext

    • BroadcastReceiver 使用的是 activitycontext

    // /frameworks/base/core/java/android/app/Activity.java
    
    // getBaseContext。这个是 ContextWrapper 中的 mBase 对象,也就是ContextImpl,也是 context 接口的真正逻辑实现
    
    @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);
        }
    

    如果当我们的代码长时间持有了 activitycontext,如静态引用或者单例类,那么会导致 activity 无法被释放。如下面的代码:

    // 单例类在应用持续的时间都会一直存在,这样 context 也就会被一直被持有, activity 无法被回收,导致内存泄露。
    object MyClass {
        lateinit var mContext : Context
        fun showToast(context : Context){
            mContext = context
        }
    }
    

    什么时候可以使用 Application

    不涉及 UI 以及启动 Activity 操作,没有界面的 context,就不应该有操作界面的权利。使用 Application 启动的 Activity 必须指定 task 以及标记为 singleTask,因为 Application 是没有任务栈的,需要重新开一个新的任务栈。

    Context 的创建过程

    Application 是应用级别的 context,是在应用被创建的时候被创建的,是第一个被创建的 context,也是最后一个被销毁的 context。因而追踪 Application 的创建需要从应用程序的启动流程看起。应用启动的源码流程如下:

    ActivityThread.class (api29)
    
    private void handleBindApplication(AppBindData data) {
        ...
        // 创建LoadedApk对象
        data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
        ...
        Application app;
        ...
        try {
            // 创建 Application, 通过 LoadApk 来创建 ContextImpl 以及 Application
            app = data.info.makeApplication(data.restrictedBackupMode, null);
            ...
        }
        try {
            ...
            // 回调Application的onCreate方法
            mInstrumentation.callApplicationOnCreate(app);
        }
        ...
    }
    

    Activitycontext 也是在 Activity 创建的过程中被创建的,这个就涉及到 Activity 的启动流程,这里涉及到三个流程:应用程序请求 AMSAMS 处理请求,应用程序响应 Activity 创建事务:

    Activity 的创建也是由 AMS 来控制的,AMS 向应用程序进程发送消息来执行具体的启动逻辑。最后会执行到 handleLaunchActivity 这个方法

    ActivityThread.class(api29)
    public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
        ...
        final Activity a = performLaunchActivity(r, customIntent);
        ...
       return a;
    }
    

    四大组件的创建都会有这个过程:

    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,
            ActivityManager.getService());
    service.onCreate();
    

    相关文章

      网友评论

          本文标题:Context

          本文链接:https://www.haomeiwen.com/subject/fnmzgktx.html