Android source code analysis in Context (a)

Disclaimer: This article is a blogger original article, reproduced welcome but must indicate the source Thank you! https://blog.csdn.net/dongxianfei/article/details/52303847

1. Background

As Android developers believe everyone should understand the Context object, right? We usually get either resources or do other operations, sometimes need to pass a Context object, but sometimes we pass Activity object program does not throw an exception error, a lot of people will feel strange. In addition, we usually sometimes used getApplication and getApplicationContext methods, but both what difference does it make? Well, today we have to and we talk about Context object and its sub-class of Android.

2, Context diagram

Let's look at the source code introduction Context class

/**
 * 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 {

}

As can be seen from the comments, Context provides a global information application environment, allows the resource type and get the application, it is an abstract class, Android provides for its implementation class, through its implementation class allows us to obtain application resources and classes (such as starting Activity, receiving the Intent, a broadcast transmission, etc.), that there are many other methods abstract, it is equivalent to providing a common API.

Context There are many sub-categories in Android, but here we analyze daily more widely used subclass. They look at the diagram:

FIG Context subclass relationships

As can be seen from the figure, Context direct subclass ContextImpl and ContextWrapper (later analysis of the roles of the two), and both the Service Application similar, are inherited ContextWrapper, inherited from the Activity ContextThemeWrapper, because there Activity Theme.

Next we look at the source code control diagram.

3, source code analysis

Let's look at the implementation class Context class ContextImpl categories:

/**
 * Common implementation of Context API, which provides the base
 * context object for Activity and other application components.
 */
class ContextImpl extends Context {

}

It implements all the methods of Context.

Take a look at another subclass Context class:

/**
 * 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 {
    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;
    }

See the class name of the class probably understand the role of this class, this class is for the Context class wrapper class, internal class contains a reference to the class ContextImpl mBase, so it should now know the role ContextImpl class, right? Context class is really implementer. This leads to a design pattern - Decorator Pattern (ContextWrapper Context is the decorator, and ContextImpl is the real implementers).

Next we take a look at the subclass ContextWrapper of ContextThemeWrapper categories:

/**
 * A ContextWrapper that allows you to modify the theme from what is in the 
 * wrapped context. 
 */
public class ContextThemeWrapper extends ContextWrapper {

}

This class contains methods to set the theme of the interior, namely android: theme attribute.

Finally, we look Activity, Service and Application source code:

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback {

}

public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {

}

public class Application extends ContextWrapper implements ComponentCallbacks2 {

}

These are the usual relationship between Context and its subclasses.

4, the process of creating various subclasses of Context

In the previous article we said the start-up process Activity Activity start entry process source code analysis of (a) , is not very clear if we can go read it.

(1) Activity is instantiated source ContextImpl

Start by startActivity methods will eventually call the new Activity handleLaunchActivity method ActivityThread class inside the method calls performLaunchActivity method to create the Activity object, we enter the process.

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //创建Activity对象
    Activity activity = null;
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);

        try {       
            //(1)这里调用LoadedApk的makeApplication
            Application app = r.packageInfo.makeApplication(false, 
mInstrumentation);

            //......
            if (activity != null) {
            //(2)创建Context对象
            Context appContext = createBaseContextForActivity(r, activity);
            //......

            //(3)将创建的appContext对象传入到Activity的attach方法中
            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);
        }
}

We first look (1) of the Code, where the Application object is created by makeApplication method LoadedApk, the paper we analyze later.

(2) at the Context object is created by passing current method createBaseContextForActivity Activity object, we enter the process.

private Context createBaseContextForActivity(ActivityClientRecord r,
            final Activity activity) {
        //通过调用ContextImpl的静态方法createActivityContext来创建ContextImpl,我们后续会详细阐述该方法
        ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);
        //这里需要重点关注下面这句,ContextImpl类有一个成员变量mOuterContext,通过下面语句将Activity赋值给mOuterContext变量,是ContextImpl持有Activity的引用
        appContext.setOuterContext(activity);
        Context baseContext = appContext;

        //......
        //返回ContextImpl对象
        return baseContext;
}

(3) at the newly created object ContextImpl Activity transmitted to the attach method.

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) {
        //此处调用父类ContextThemeWrapper的attachBaseContext方法并最终调用ContextWrapper类的attachBaseContext方法,将新创建的ContextImpl对象赋值给ContextWrapper的成员变量mBase,这样ContextWrapper及其子类的mBase成员变量就被实例化为ContextImpl对象。
        attachBaseContext(context);

        //......

        mMainThread = aThread;
        mInstrumentation = instr;
        mToken = token;
        mIdent = ident;
        //此处会将通过LoadedApk.makeApplication创建的Application对象赋值给mApplication变量
        mApplication = application;
        mIntent = intent;
        mReferrer = referrer;
        mComponent = intent.getComponent();
        mActivityInfo = info;
        mTitle = title;
        mParent = parent;
        mEmbeddedID = id;

        //......
}

As can be seen from the above analysis, Activity ContextImpl objects referenced by members mBase ContextWrapper, i.e. Activity specific component may be performed an operation (Start Service, etc.) by the ContextImpl object.
Meanwhile ContextImpl class and by its own member variables mOuterContext quoted Activity associated with it, so ContextImpl class can also operate Activity.

Therefore, there is a description of an Activity Context, and the same life cycle and the Activity class.

2, Service of ContextImpl instantiation Source

We usually start the Service by startService and bindService way, but whether to create a new Service which ultimately by handleCreateService ActivityThread class () method to perform the operation by which way we look at the source code.

private void handleCreateService(CreateServiceData data) {
    //创建Service对象
    Service service = null;
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        service = (Service) cl.loadClass(data.info.name).newInstance(); 

        //(1)通过ContextImpl的静态方法createAppContext创建ContextImpl对象
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);

        //(2)和之前的Activity一样,ContextImpl中有一个成员变量mOuterContext,此处将Service对象赋值给mOuterContext,以便让ContextImpl内部持有一个Service对象的引用
        context.setOuterContext(service);

        //(3)这里调用LoadedApkmakeApplication
        Application app = packageInfo.makeApplication(false, mInstrumentation);

        //(4)这里调用Serviceattach方法
        service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
        service.onCreate();
        mServices.put(data.token, service);
}

(1) to create ContextImpl at ContextImpl by calling the static method createAppContext, we will elaborate on the follow-up method.
(2) prior to and at the Activity as a reference to the current object holds ContextImpl Service.
Call LoadedApk object at (3) makeApplication method to create the Application object, text analysis after us.
(4) Service calls attach method here, we enter the process.

public final void attach(
            Context context,
            ActivityThread thread, String className, IBinder token,
            Application application, Object activityManager) {
        //这里调用父类的attachBaseContext方法
        attachBaseContext(context);
        mThread = thread;           // NOTE:  unused - remove?
        mClassName = className;
        mToken = token;
        ////此处会将通过LoadedApk.makeApplication创建的Application对象赋值给mApplication变量
        mApplication = application;
        mActivityManager = (IActivityManager)activityManager;
        mStartCompatibility = getApplicationInfo().targetSdkVersion
                < Build.VERSION_CODES.ECLAIR;
    }

ContextWrapper the member variables by calling the parent class ContextWrapper Service attachBaseContext method of mBase is assigned to ContextImpl objects, both for ContextWrapper and its subclasses have ContextImpl object.
It showed a Service there is a Context, and the same life cycle and Service category.

3, Application Examples of the source of ContextImpl

Each App has a global Application object, and is the same throughout the life cycle of App, is in the process of creating Application handleBindApplication ActivityThread class () method, and is transported to create ContextImpl makeApplication LoadedApk class method in the method we enter makeApplication method.

public final class LoadedApk {

    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        //当Application不为null时,直接返回该对象
        if (mApplication != null) {
            return mApplication;
        }

        Application app = null;

        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                initializeJavaContextClassLoader();
            }
            //(1)创建ContextImpl对象
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //(2)创建Application对象
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            //(3)将新创建的Application对象赋值给ContextImpl对象的成员变量mOuterContext,既让ContextImpl内部持有Application对象的引用
            appContext.setOuterContext(app);
        } 

        //此处将创建的Application对象赋值给本类的mApplication变量
        mApplication = app;
        //......

        return app;
    }
}

(1) at ContextImpl to create objects through static methods createAppContext ContextImpl, the paper we analyze later.
(2) at the Application object to create an object by calling Instrumentation newApplication method, we enter the process.

public Application newApplication(ClassLoader cl, String className, Context context)throws InstantiationException, IllegalAccessException,ClassNotFoundException {

        return newApplication(cl.loadClass(className), context);

    }

static public Application newApplication(Class<?> clazz, Context context)throws InstantiationException, IllegalAccessException,ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        //继续进入Application的attached方法
        app.attach(context);
        return app;
    }
 final void attach(Context context) {
        //终于看到了我们要找的attachBaseContext方法了
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }

As before, passing through various methods, call the parent class method attachBaseContext Application will ContextImpl objects assigned to the member variables ContextWrapper class mBase, eventually ContextWrapper and its subclasses contain ContextImpl object.

(3) Application at the newly created object is assigned to the member variables ContextImpl object mOuterContext, both for internal ContextImpl holds Application object.

So let each held between both objects, may additionally contain a description on an Application Context, and the same life cycle and Application class, and in the life cycle of the application is the same.

5, Context uniqueness of access to resources

Through our previous analysis of different subclasses Context, we know there are a lot of Context objects, resources that we usually get when accessing resources getResources is the same copy? We enter to view the source code.

class ContextImpl extends Context {
    private final ResourcesManager mResourcesManager;
    private final Resources mResources;

      @Override
    public AssetManager getAssets() {
        return getResources().getAssets();
    }

    @Override
    public Resources getResources() {
        return mResources;
    }
}

We usually get through getResources resource object method is to obtain the member variable mResources ContextImpl by the above method, then assign it where it is?

private ContextImpl(ContextImpl container, ActivityThread mainThread,LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,Display display, Configuration overrideConfiguration) {
    //......
    //单例模式获得ResourcesManager对象
    mResourcesManager = ResourcesManager.getInstance();

    //由于packageInfo只有一个,所以resources是同一份
    Resources resources = packageInfo.getResources(mainThread);
        if (resources != null) {
            if (activityToken != null
                    || displayId != Display.DEFAULT_DISPLAY
                    || overrideConfiguration != null
                    || (compatInfo != null && compatInfo.applicationScale
                            != resources.getCompatibilityInfo().applicationScale)) {
                //由于mResourcesManager是单例,所以resources是同一份
                resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
                        packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
                        packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
                        overrideConfiguration, compatInfo, activityToken);
            }
        }
        //最后赋值给mResources成员变量
        mResources = resources;
}

It can be seen getResources is available with a resource, while in the previous Activity, Service as well as Application explanation, they need to create ContextImpl objects, they create the object using a createActivityContext and createAppContext way we look at these two method.

static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
        return new ContextImpl(null, mainThread,
                packageInfo, null, null, false, null, null);
    }


static ContextImpl createActivityContext(ActivityThread mainThread,LoadedApk packageInfo, IBinder activityToken) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
        if (activityToken == null) throw new IllegalArgumentException("activityInfo");
        return new ContextImpl(null, mainThread,
                packageInfo, activityToken, null, false, null, null);
    }

Either way, ultimately calling ContextImpl constructor to create ContextImpl objects, so they are using the same copy of the resource.

6, getApplication and getApplicationContext difference

Remember the beginning of the article say that we want to discuss the difference between these two methods do? We now from the perspective of the source code to resolve it.

We first look at getApplication method, you will find no Context and Application of the method, which is in the Activity and Service, we look at the source code.

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback {

    /** Return the application that owns this activity. */
    public final Application getApplication() {
        return mApplication;
    }
}

public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
    /** Return the application that owns this service. */
    public final Application getApplication() {
        return mApplication;
    }
}

They both offer such a method, and the return value is the Application object mApplication, then this mApplication variable assignment where it? Through our previous Activity and attached source of known methods Service, mApplication value of the variable here is the return value LoadedApk.makeApplication () method prior to the adoption.
So different Activity and Service Application are returned with a global object.

We take a look at getApplicationContext method, which is defined in the Context is to achieve its subclasses ContextImpl.

class ContextImpl extends Context {
 @Override
    public Context getApplicationContext() {
        //此处的mPackageInfo就是LoadedApk对象
        return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
    }
}

public final class LoadedApk {
    Application getApplication() {
        return mApplication;
    }
}

From the source of this method, the return is a member variable LoadedApk class mApplication, and mApplication is assigned in makeApplication method LoadedApk class in.

From the above source code, getApplication () and getApplicationContext () returns the same type of variable.

Well, today Context source code analysis on the matter so far, I hope you like thank you!

Guess you like

Origin blog.csdn.net/dongxianfei/article/details/52303847