Context分析

核心Context以及之间的关系:

  • Context:抽象的API接口
  • ContextWrapper:Context的代理,具体作用在于在不影响Context的情况下,获得自己的特有行为。具体的实现是由其依赖的ContextImpl实现的
  • ContextImpl:实际的实现类
  • ContextThemeWrapper:提供了可修改theme的Context

Context个数疑惑

Android应用程序只有四大组件,而其中两大组件都继承自Context,另外每个应用程序还有一个全局的Application对象。所以在我们了解了上面继承关系之后我们就可以计算出来Context总数,如下:

APP Context总数 = Application数(1) + Activity数(Customer) + Service数(Customer);

Activity中ContextImpl实例化源码分析

  • 通过startActivity启动一个新的Activity时系统会回调ActivityThread的handleLaunchActivity()方法,该方法内部会调用performLaunchActivity()方法去创建一个Activity实例,然后回调Activity的onCreate()等方法。所以Activity的ContextImpl实例化是在ActivityThread类的performLaunchActivity方法中。
    //---performLaunchActivity
    //创建一个Context对象
    Context appContext = createBaseContextForActivity(r, activity);
    
  • createBaseContextForActivity的具体实现如下:
    private Context createBaseContextForActivity(ActivityClientRecord r,
              final Activity activity) {
          //实质就是new一个ContextImpl对象,调运ContextImpl的有参构造初始化一些参数    
          ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);
          //特别特别留意这里!!!
          //ContextImpl中有一个Context的成员叫mOuterContext,通过这条语句就可将当前新Activity对象赋值到创建的ContextImpl的成员mOuterContext(也就是让ContextImpl内部持有Activity)。
          appContext.setOuterContext(activity);
          //创建返回值并且赋值
          Context baseContext = appContext;
          ......
          //返回ContextImpl对象
          return baseContext;
      }
    
    调用ContextImpl的静态构造方法,创建一个ContextImpl对象,同时将当前的activity传入到这个ContextImpl对象中,使其持有这个activity。
  • Activity的attach的具体实现:
    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) {
          //特别特别留意这里!!!
          //与上面createBaseContextForActivity方法中setOuterContext语句类似,不同的在于:
          //通过ContextThemeWrapper类的attachBaseContext方法,将createBaseContextForActivity中实例化的ContextImpl对象传入到ContextWrapper类的mBase变量,这样ContextWrapper(Context子类)类的成员mBase就被实例化为Context的实现类ContextImpl
          attachBaseContext(context);
          ......
      }
    
    由于Activity继承的是ContextWrapper类,而其具体实现是ContextImpl,所以这个的操作就是将生成的ContextImpl对象传给ContextWrapper。

总结

Activity通过ContextWrapper的成员mBase来引用了一个ContextImpl对象,这样,Activity组件以后就可以通过这个ContextImpl对象来执行一些具体的操作(启动Service等);同时ContextImpl类又通过自己的成员mOuterContext引用了与它关联的Activity,这样ContextImpl类也可以操作Activity。

由此说明一个Activity就有一个Context,而且生命周期和Activity类相同。

Application中ContextImpl实例化源码分析

  • 创建Application的过程也在ActivityThread类的handleBindApplication()方法完成相关数据操作。而ContextImpl的创建是在该方法中调运LoadedApk类的makeApplication方法中实现。
    try {
              java.lang.ClassLoader cl = getClassLoader();
              if (!mPackageName.equals("android")) {
                  initializeJavaContextClassLoader();
              }
              //不做过多解释,创建一个Context对象
              ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
              //将Context传入Instrumentation类的newApplication方法
              app = mActivityThread.mInstrumentation.newApplication(
                      cl, appClass, appContext);
              //特别特别留意这里!!!
              //ContextImpl中有一个Context的成员叫mOuterContext,通过这条语句就可将当前新Application对象赋值到创建的ContextImpl的成员mOuterContext(也就是让ContextImpl内部持有Application)。
              appContext.setOuterContext(app);
          } catch (Exception e) {
              ......
          }
    
  • Instrmentation.newApplication创建新的application对象,并将Context通过attach传给application。
    static public Application newApplication(Class<?> clazz, Context context)
              throws InstantiationException, IllegalAccessException, 
              ClassNotFoundException {
          Application app = (Application)clazz.newInstance();
          //继续传递context
          app.attach(context);
          return app;
      }
    
  • attach方法
    final void attach(Context context) {
          //特别特别留意这里!!!
          //与上面makeApplication方法中setOuterContext语句类似,不同的在于:
          //通过ContextWrapper类的attachBaseContext方法,将makeApplication中实例化的ContextImpl对象传入到ContextWrapper类的mBase变量,这样ContextWrapper(Context子类)类的成员mBase就被实例化为Application的实现类ContextImpl
          attachBaseContext(context);
          ......
      }
    
    这个跟Activity一样的,将Application实例绑定到这个Context上。

最后通过setOuterContext将Application对象传给Context,让Context持有Application对象。

Service中ContextImpl实例化源码分析

同样是在ActivityThread中的,handleCreateService实现,大致的逻辑和activity和application一样。

private void handleCreateService(CreateServiceData data) {
        ......
        //类似上面Activity的创建,这里创建service对象实例
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            ......
        }

        try {
            ......
            //不做过多解释,创建一个Context对象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            //特别特别留意这里!!!
            //ContextImpl中有一个Context的成员叫mOuterContext,通过这条语句就可将当前新Service对象赋值到创建的ContextImpl的成员mOuterContext(也就是让ContextImpl内部持有Service)。
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            //将上面创建的context传入到service的attach方法
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            service.onCreate();
            ......
        } catch (Exception e) {
            ......
        }
    }

getApplicationgetApplicationContext的区别

getApplication:这里的mApplication是Service或Activityattach时传入得,也就是makeApplication所返回的对象。所以不同的Activity和Service返回的Application均为同一个全局对象。

public final Application getApplication() {
    return mApplication;
}

getApplicationContext:这个是Context中定义的,返回值是Context类型,返回对象和上面通过Service或者Activity的getApplication返回的是一个对象。

@Override
public Context getApplicationContext() {
    return (mPackageInfo != null) ? mPackageInfo.getApplication() : mMainThread.getApplication();
}

所以,这两个方法返回的是同一个值,只是返回的类型就差异,记忆依附的环境不一样而已,都是makeApplication的对象。

总结

综上,不同的Context的生命周期是不一样的,跟它绑定的环境是有关系的,比如Application的Context生命周期与应用程序完全相同,Activity或者Service的Context与他们各自类生命周期相同。所以,要防止有关的Context的内存泄露,就要根据实际情况,看看他的生命周期。

results matching ""

    No results matching ""