• Android中Context认识


    基于SDK29

    1、Context作用

    ​ Context,意为上下文,阅读理解中常常有联系上下文理解的说法,这里可以认为Context是一个特定的范围,提供了整个环境的一些数据,比如Application作为Context可以注册Activity生命周期监听、获取应用进程名、获取应用资源等等,Activity作为Context可以获取资源、启动Activity、加载View等等, 具体使用见下图:

    ​ (以上图片来自博客:Android Context 上下文 你必须知道的一切)

    2、Context分析

    2.1、Context继承树

    ​ Context继承结构如下所示:

    java.lang.Object:
      android.content.Context:
        android.app.ContextImpl  (Activity和Application中mBase具体操作实现类)
      
        android.content.ContextWrapper:
          android.app.Application
          android.app.Service
    
          android.view.ContextThemeWrapper:
            android.app.Activity:
              androidx.core.app.ComponentActivity:
                androidx.activity.ComponentActivity:
                  androidx.fragment.app.FragmentActivity:
                    androidx.appcompat.app.AppCompatActivity
    

    ​ 四大组件中Activity继承自ContextThemeWrapper,Service和Application继承自ContextWrapper。

    2.2、ContextImpl类

    ​ ContextImpl类直接继承自Context类,位于android.app包下,提供了Context抽象方法的直接实现, 包括getAssets、getResources、getPackageManager等。

    2.3、ContextWrapper分析

    ​ ContextWrapper使用静态代理的模式来管理Context,内部所有的操作都是通过Context类型的mBase来具体实现,如getResources()等。通过构造方法或者attachBaseContext方法对mBase赋值。

    public class ContextWrapper extends Context {
        Context mBase;
    
        public ContextWrapper(Context base) {
            mBase = base;
        }
        
        protected void attachBaseContext(Context base) {
            if (mBase != null) {
                throw new IllegalStateException("Base context already set");
            }
            mBase = base;
        }
    
        public Context getBaseContext() {
            return mBase;
        }
    
        @Override
        public Resources getResources() {
            return mBase.getResources();
        }
        
        ...
    }
    

    2.4、ContextThemeWrapper分析

    ​ ContextThemeWrapper与ContextWrapper主要区别在于:前者能够直接处理主题,根据主题样式的id(mThemeResource)生成对应的主题Theme(mTheme),而后者需要由内部的mBase进行处理。

    public class ContextThemeWrapper extends ContextWrapper {
        private int mThemeResource;
        private Resources.Theme mTheme;
    
        public ContextThemeWrapper() {
            super(null);
        }
    
        public ContextThemeWrapper(Context base, @StyleRes int themeResId) {
            super(base);
            mThemeResource = themeResId;
        }
    
        public ContextThemeWrapper(Context base, Resources.Theme theme) {
            super(base);
            mTheme = theme;
        }
    
        @Override
        protected void attachBaseContext(Context newBase) {
            super.attachBaseContext(newBase);
        }
    
        @Override
        public void setTheme(int resid) {
            if (mThemeResource != resid) {
                mThemeResource = resid;
                initializeTheme();
            }
        }
    
        public void setTheme(@Nullable Resources.Theme theme) {
            mTheme = theme;
        }
    
        @Override
        public int getThemeResId() {
            return mThemeResource;
        }
    
        @Override
        public Resources.Theme getTheme() {
            if (mTheme != null) {
                return mTheme;
            }
    
            mThemeResource = Resources.selectDefaultTheme(mThemeResource,
                    getApplicationInfo().targetSdkVersion);
            initializeTheme();
    
            return mTheme;
        }
    
        private void initializeTheme() {
            final boolean first = mTheme == null;
            if (first) {
                mTheme = getResources().newTheme();
                final Resources.Theme theme = getBaseContext().getTheme();
                if (theme != null) {
                    mTheme.setTo(theme);
                }
            }
            onApplyThemeResource(mTheme, mThemeResource, first);
        }
        
        ...
    }
    

    3、Activity以及Application创建过程

    3.1、Activity创建过程

    ​ Activity创建在ActivityThread类的performLaunchActivity方法中,部分代码如下:

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        
    
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }
    
        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    
            ...
    
            if (activity != null) {
                ...
                
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback,
                        r.assistToken);
    
                ...
                
                r.activity = activity;
            }
            r.setState(ON_CREATE);
    
            ...
    
        } catch (SuperNotCalledException e) {
            throw e;
    
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }
    
        return activity;
    }
    

    ​ 以上代码可以简单概括如下:

    ​ 首先创建ContextImpl的实例appContext, 然后通过Instrumentation类的newActivity方法生成Activity,最后调用Activity的attach方法将appContext关联到Activity的mBase,从而将Activity中有关Context的操作委托给ComtextImpl类的实例。

    3.2、Application创建过程

    ​ 和Activity一样,Application内部的mBase也是ContextImpl,创建Activity时会检查Application是否存在,不存在则创建。

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);   
        } catch (SuperNotCalledException e) {
            throw e;
    
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                        "Unable to start activity " + component
                        + ": " + e.toString(), e);
            }
        }
        ...
    }
    

    ​ 其中r.packageInfo为LoadApk的实例, makeApplication方法也会先创建一个ComtextImpl的实例appContext,然后调用Instrumentation的newApplication创建Application,并调用Application的attach方法将appContext关联到Application的mBase,将Application中有关Context的操作委托给ComtextImpl类的实例。部分代码如下:

    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }
    
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
    
        Application app = null;
    
        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }
    
        try {
            ...
            
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            ...
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;
    
        ...
    
        return app;
    }
    

    4、总结

    ​ 除了显示Dialog、启动Activity或者加载View,应用中用到Context的地方都可以使用Application作为Context,这样可以避免内存泄露的情况。

  • 相关阅读:
    Sqlmap使用详解
    WEB漏洞学习手册
    量压形态的使用方法
    sql执行过程及常见优化手段
    什么是JavaScript 函数作用域
    git http 拉取代码 自动输入用户名和密码
    PHP 报文件写入无权限 file_put_contents failed to open stream: Permission denied in xxxxx on line 2
    记一次 解决PHP Linux服务器报 打开文件数过多的异常
    微信开发 坑 记录帖
    python 安装 cv2 注意事项 填坑 opencv-python 找不到指定的模块
  • 原文地址:https://www.cnblogs.com/wushengwuxi/p/14578858.html
Copyright © 2020-2023  润新知