zoukankan      html  css  js  c++  java
  • Android之Context进阶

    一、Context作用是什么?

      下面看下Context源码中的注释:

    /**
     * Interface to global information about an application environment.  This is
     * an abstract class whose implementation is provided by
     * the Android system.  It
     * allows access to application-specific resources and classes, as well as
     * up-calls for application-level operations such as launching activities,
     * broadcasting and receiving intents, etc.
     */

      意思是,Context是Android系统提供的一个抽象类,Context具有应用环境的全局信息。它(Context对象)允许访问应用特定的资源和类,以及调用应用级的方法,比如:launching Activities、broadcasting和receiving intents等。

      Context抽象类及部分抽象函数:

    /**
     * Interface to global information about an application environment.  This is
     * an abstract class whose implementation is provided by
     * the Android system.  It
     * allows access to application-specific resources and classes, as well as
     * up-calls for application-level operations such as launching activities,
     * broadcasting and receiving intents, etc.
     */
    public abstract class Context {
    
        ……
    
        /**
         * Returns an AssetManager instance for the application's package.
         * <p>
         * <strong>Note:</strong> Implementations of this method should return
         * an AssetManager instance that is consistent with the Resources instance
         * returned by {@link #getResources()}. For example, they should share the
         * same {@link Configuration} object.
         *
         * @return an AssetManager instance for the application's package
         * @see #getResources()
         */
        public abstract AssetManager getAssets();
    
        /**
         * Returns a Resources instance for the application's package.
         * <p>
         * <strong>Note:</strong> Implementations of this method should return
         * a Resources instance that is consistent with the AssetManager instance
         * returned by {@link #getAssets()}. For example, they should share the
         * same {@link Configuration} object.
         *
         * @return a Resources instance for the application's package
         * @see #getAssets()
         */
        public abstract Resources getResources();
    
        /** Return PackageManager instance to find global package information. */
        public abstract PackageManager getPackageManager();
    
        /**
         * Return the context of the single, global Application object of the
         * current process.  This generally should only be used if you need a
         * Context whose lifecycle is separate from the current context, that is
         * tied to the lifetime of the process rather than the current component.
         *
         * <p>Consider for example how this interacts with
         * {@link #registerReceiver(BroadcastReceiver, IntentFilter)}:
         * <ul>
         * <li> <p>If used from an Activity context, the receiver is being registered
         * within that activity.  This means that you are expected to unregister
         * before the activity is done being destroyed; in fact if you do not do
         * so, the framework will clean up your leaked registration as it removes
         * the activity and log an error.  Thus, if you use the Activity context
         * to register a receiver that is static (global to the process, not
         * associated with an Activity instance) then that registration will be
         * removed on you at whatever point the activity you used is destroyed.
         * <li> <p>If used from the Context returned here, the receiver is being
         * registered with the global state associated with your application.  Thus
         * it will never be unregistered for you.  This is necessary if the receiver
         * is associated with static data, not a particular component.  However
         * using the ApplicationContext elsewhere can easily lead to serious leaks
         * if you forget to unregister, unbind, etc.
         * </ul>
         */
        public abstract Context getApplicationContext();
    
        /** Return the name of this application's package. */
        public abstract String getPackageName();
    
        ……
        
    }

    二、Context是一个抽象类,那么,它的实现类有哪些?

      Context的实现类分别是ContextImpl和ContextWrapper。

      ContextImpl类:

      源码:frameworks/base/core/java/android/app/ContextImpl.java

    /**
     * Common implementation of Context API, which provides the base
     * context object for Activity and other application components.
     */
    class ContextImpl extends Context {
        private final static String TAG = "ContextImpl";
        private final static boolean DEBUG = false;
    
        private static final String XATTR_INODE_CACHE = "user.inode_cache";
        private static final String XATTR_INODE_CODE_CACHE = "user.inode_code_cache";
    
        /**
         * Map from package name, to preference name, to cached preferences.
         */
        @GuardedBy("ContextImpl.class")
        @UnsupportedAppUsage
        private static ArrayMap<String, ArrayMap<File, SharedPreferencesImpl>> sSharedPrefsCache;
    
        /**
         * Map from preference name to generated path.
         */
        @GuardedBy("ContextImpl.class")
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
        private ArrayMap<String, File> mSharedPrefsPaths;
    
        @UnsupportedAppUsage
        final @NonNull ActivityThread mMainThread;
        @UnsupportedAppUsage
        final @NonNull LoadedApk mPackageInfo;
        @UnsupportedAppUsage
        private @Nullable ClassLoader mClassLoader;
    
        private final @Nullable IBinder mToken;
    
        private final @NonNull UserHandle mUser;
    
        @UnsupportedAppUsage
        private final ApplicationContentResolver mContentResolver;
    
        @UnsupportedAppUsage
        private final String mBasePackageName;
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
        private final String mOpPackageName;
    
        ……
        
    }

      ContextImplt类应用在哪里?

      应用中Application、Acitivity、Service、View等里的Context对象都是ContextImpl的实例化。

      通过ContextImpl对象能够获取package信息、package管理、资源、资源管理、主题等信息。

      ContextWrapper类:

      源码:frameworks/base/core/java/android/content/ContextWrapper.java

    /**
     * Proxying implementation of Context that simply delegates all of its calls to
     * another Context.  Can be subclassed to modify behavior without changing
     * the original Context.
     */
    public class ContextWrapper extends Context {
        @UnsupportedAppUsage
        Context mBase;
    
        public ContextWrapper(Context base) {
            mBase = base;
        }
    
        /**
         * Set the base context for this ContextWrapper.  All calls will then be
         * delegated to the base context.  Throws
         * IllegalStateException if a base context has already been set.
         *
         * @param base The new base context for this wrapper.
         */
        protected void attachBaseContext(Context base) {
            if (mBase != null) {
                throw new IllegalStateException("Base context already set");
            }
            mBase = base;
        }
    
        /**
         * @return the base context as set by the constructor or setBaseContext
         */
        public Context getBaseContext() {
            return mBase;
        }
    
        @Override
        public AssetManager getAssets() {
            return mBase.getAssets();
        }
    
        @Override
        public Resources getResources() {
            return mBase.getResources();
        }
    
        @Override
        public PackageManager getPackageManager() {
            return mBase.getPackageManager();
        }
    
        @Override
        public ContentResolver getContentResolver() {
            return mBase.getContentResolver();
        }
    
        @Override
        public Looper getMainLooper() {
            return mBase.getMainLooper();
        }
    
        @Override
        public Executor getMainExecutor() {
            return mBase.getMainExecutor();
        }
    
        @Override
        public Context getApplicationContext() {
            return mBase.getApplicationContext();
        }
    
        @Override
        public void setTheme(int resid) {
            mBase.setTheme(resid);
        }
    
        /** @hide */
        @Override
        @UnsupportedAppUsage
        public int getThemeResId() {
            return mBase.getThemeResId();
        }
    
        @Override
        public Resources.Theme getTheme() {
            return mBase.getTheme();
        }
    
        @Override
        public ClassLoader getClassLoader() {
            return mBase.getClassLoader();
        }
    
        @Override
        public String getPackageName() {
            return mBase.getPackageName();
        }
    
        ……
    
    }

      ContextWrapper是Application类、Activity类、Service类的基类。

      ContextWrapper中的函数实现都是通过静态代理,通过mBase(ContextImpl实例)对象获取的。

    三、应用中哪些组件拥有Context对象

      应用中Application、Activity、Service拥有自己的Context对象,而Broadcasting、Content provider是没有自己的Context对象的,是由外部传入的。

      1. Application Context实现及创建

      Application类:
    /**
     * Base class for maintaining global application state. You can provide your own
     * implementation by creating a subclass and specifying the fully-qualified name
     * of this subclass as the <code>"android:name"</code> attribute in your
     * AndroidManifest.xml's <code>&lt;application&gt;</code> tag. The Application
     * class, or your subclass of the Application class, is instantiated before any
     * other class when the process for your application/package is created.
     *
     * <p class="note"><strong>Note: </strong>There is normally no need to subclass
     * Application.  In most situations, static singletons can provide the same
     * functionality in a more modular way.  If your singleton needs a global
     * context (for example to register broadcast receivers), include
     * {@link android.content.Context#getApplicationContext() Context.getApplicationContext()}
     * as a {@link android.content.Context} argument when invoking your singleton's
     * <code>getInstance()</code> method.
     * </p>
     */
    public class Application extends ContextWrapper implements ComponentCallbacks2 {
        private static final String TAG = "Application";
        @UnsupportedAppUsage
        private ArrayList<ComponentCallbacks> mComponentCallbacks =
                new ArrayList<ComponentCallbacks>();
        @UnsupportedAppUsage
        private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
                new ArrayList<ActivityLifecycleCallbacks>();
        @UnsupportedAppUsage
        private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null;
    
        /** @hide */
        @UnsupportedAppUsage
        public LoadedApk mLoadedApk;
    
    ……
    
    }

      Application继承链:Application -> ContextWrapper -> Context。

      Application创建

     

      AMS通知应用创建Application,创建Application实现,在ActivityThread类中handleBindApplication(...)函数:

    @UnsupportedAppUsage
    private void handleBindApplication(AppBindData data) {
        ……
        try {
            // If the app is being launched for full backup or restore, bring it up in
            // a restricted environment with the base application class.
            app = data.info.makeApplication(data.restrictedBackupMode, null);
    
            ……
        } finally {
            ……
        }
    
        ……
    }

      LoadedApk类makeApplication(...)函数实现:

      LoadedApk源码:frameworks/base/core/java/android/app/LoadedApk.java

    @UnsupportedAppUsage
    public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }
    
        ……
    
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        // The network security config needs to be aware of multiple
        // applications in the same process to handle discrepancies
        NetworkSecurityConfigProvider.handleNewApplication(appContext);
        app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
    
        ……
    }

      创建Application实现,Instrumentation类中:

      Instrumentation源码:frameworks/base/core/java/android/app/Instrumentation.java

    /**
     * Perform instantiation of the process's {@link Application} object.  The
     * default implementation provides the normal system behavior.
     * 
     * @param cl The ClassLoader with which to instantiate the object.
     * @param className The name of the class implementing the Application
     *                  object.
     * @param context The context to initialize the application with
     * 
     * @return The newly instantiated Application object.
     */
    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = getFactory(context.getPackageName())
                .instantiateApplication(cl, className);
        app.attach(context);
        return app;
    }

      从实现中可以看出,Applicaiton的Context是ContextImpl实例对象,后面调用app.attach()函数。

      Applicatoin类:

    public class Application extends ContextWrapper implements ComponentCallbacks2 {
    
        ……
    
        @UnsupportedAppUsage
        /* package */ final void attach(Context context) {
            attachBaseContext(context);
            mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
        }
    
        ……
    
    }

      由于Appliation继承ContextWrapper类,最后会调用到函数attachBaseContext()为ContextWrapper的mBase成员变量赋值:

      ContextWrapper类:

    /**
     * Proxying implementation of Context that simply delegates all of its calls to
     * another Context.  Can be subclassed to modify behavior without changing
     * the original Context.
     */
    public class ContextWrapper extends Context {
        @UnsupportedAppUsage
        Context mBase;
    
        public ContextWrapper(Context base) {
            mBase = base;
        }
    
        /**
         * Set the base context for this ContextWrapper.  All calls will then be
         * delegated to the base context.  Throws
         * IllegalStateException if a base context has already been set.
         *
         * @param base The new base context for this wrapper.
         */
        protected void attachBaseContext(Context base) {
            if (mBase != null) {
                throw new IllegalStateException("Base context already set");
            }
            mBase = base;
        }
    
        @Override
        public Context getApplicationContext() {
            return mBase.getApplicationContext();
        }
    
        ……
    
    }

      在ContextWrapper类中将ContextImpl实例对象赋值给mBase,而在ContextWrapper类的函数实现都是通过调用mBase对象调用具体实现函数,这里用到了静态代理设计模式

      如果,Hook了mBase,就可以将Application里的Context替换成开发自己的Context实现,在一些SDK里是这样用的。比如:多语言语料更新的SDK库。

      2. Activity Context创建及实现

    public class Activity extends ContextThemeWrapper
            implements LayoutInflater.Factory2,
            Window.Callback, KeyEvent.Callback,
            OnCreateContextMenuListener, ComponentCallbacks2,
            Window.OnWindowDismissedCallback,
            AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
           …… 
    }

      Activity继承链:Activity -> ContextThemeWrapper -> ContextWrapper -> Context

      Activity创建:

      源码:frameworks/base/core/java/android/app/ActivityThread.java

      performLaunchActivity(...)函数实现Activity创建:

    /**  Core implementation of activity launch. */
    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);
            }
        }
    
        ……
    
        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);
        
        ……
    
        return activity;
    }

       通过createBaseContextForActivity()函数创建ContextImpl类型的Context对象。mInstrumentation.newActivity(...)函数创建Activity对象。

      Instantiation类中newActivity(...)函数:

      源码:frameworks/base/core/java/android/app/Instantiation.java

    /**
     * Perform instantiation of the process's {@link Activity} object.  The
     * default implementation provides the normal system behavior.
     * 
     * @param cl The ClassLoader with which to instantiate the object.
     * @param className The name of the class implementing the Activity
     *                  object.
     * @param intent The Intent object that specified the activity class being
     *               instantiated.
     * 
     * @return The newly instantiated Activity object.
     */
    public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        String pkg = intent != null && intent.getComponent() != null
                ? intent.getComponent().getPackageName() : null;
        return getFactory(pkg).instantiateActivity(cl, className, intent);
    }

      在返回Activity对象后,通过调用activity.attach(...)函数为ContextImpl对象成员变量mBase赋值,流程和Applicaiton一样,在performLaunchActivity(...)函数中:

    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    
        ……
    
        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);
        
        ……
    
        return activity;
    }

      在Activity类中attach(...)函数实现:

    @UnsupportedAppUsage
    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, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
    
        attachBaseContext(context);
    
        ……
        
    }

      ContextWrapper类中attachBaseContext(Context base)函数实现:

    /**
        * Set the base context for this ContextWrapper.  All calls will then be
        * delegated to the base context.  Throws
        * IllegalStateException if a base context has already been set.
        *
        * @param base The new base context for this wrapper.
        */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

      3. Service Context的创建与实现

    public abstract class Service extends ContextWrapper implements ComponentCallbacks2,
            ContentCaptureManager.ContentCaptureClient {
        ……
    }

      Service继承链:Service -> ContextWrapper -> Context

      Service创建实现:

      源码:frameworks/base/core/java/android/app/ActivityThread.java

      创建Service函数:handleCreateService(...):

    @UnsupportedAppUsage
    private void handleCreateService(CreateServiceData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
    
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
    
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
            // Service resources must be initialized with the same loaders as the application
            // context.
            context.getResources().addLoaders(
                    app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
    
            context.setOuterContext(service);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
    }

      通过ContextImpl.createAppContext(...)函数创建ContextImpl实例对象context。

      通过packageInfo.getAppFactory().instantiateService(...)函数创建Service对象。

      最后,通过attach(context, ...)函数,将context对象作为参数传入,在调用attachBaseContext(context)函数给ContextWrapper类的成员变量mBase(ContextImpl)。流程和Application一样。

      Service类中attach(...)函数实现:

    @UnsupportedAppUsage
    public final void attach(
            Context context,
            ActivityThread thread, String className, IBinder token,
            Application application, Object activityManager) {
        attachBaseContext(context);
        mThread = thread;           // NOTE:  unused - remove?
        mClassName = className;
        mToken = token;
        mApplication = application;
        mActivityManager = (IActivityManager)activityManager;
        mStartCompatibility = getApplicationInfo().targetSdkVersion
                < Build.VERSION_CODES.ECLAIR;
    
        setContentCaptureOptions(application.getContentCaptureOptions());
    }

      ContextWrapper类中attachBaseContext(Context base)函数实现:

    /**
        * Set the base context for this ContextWrapper.  All calls will then be
        * delegated to the base context.  Throws
        * IllegalStateException if a base context has already been set.
        *
        * @param base The new base context for this wrapper.
        */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

      

    四、总结

       1. 在应用中,一共有多少个Context对象?

        Application、Activity、Service拥有自己的Context对象,而广播、Content Provider的Context对象是外部传入的。所以,Context对象数量 = Application对象 + Activity对象 + Service对象。

      2. Context作用?

        Context,它允许访问应用特定的资源和类,也可以调用应用级别的方法,比如:startActivity(...),sendBroadcase(...),getResources()等。

      

      

      

  • 相关阅读:
    数据挖掘实践(45):实战--啤酒产量时序分析(三)
    数据挖掘实践(44):实战--啤酒产量时序分析(二)
    数据挖掘实践(43):实战--啤酒产量时序分析(一)
    数据挖掘实践(42):算法基础(十四)时间序列分析(五)
    Java 之 数组 案例(不重复的数组&回形数)
    Java 之 数组中常见的异常
    Java 之 数组 Arrays 工具类
    Java 之 数组常用算法
    Java 之 多维数组(二维数组)
    Java 之 一维数组
  • 原文地址:https://www.cnblogs.com/naray/p/15246664.html
Copyright © 2011-2022 走看看