当前位置: 移动技术网 > 移动技术>移动开发>Android > android中Context深入详解

android中Context深入详解

2019年07月24日  | 移动技术网移动技术  | 我要评论

以下分别通过context认知角度,继承关系,对象创建等方面android中context做了深入的解释,一起学习下。

1、context认知。

context译为场景,一个应用程序可以认为是一个工作环境,在这个工作环境中可以存在许多场景,coding代码的场景 ,打电话的场景,开会的场景。这些场景可以类比不同的activity,service。

2、从两个角度认识context。

第一:activity继承自context,同时activity还实现了其他的interface,我们可以这样看,activity在语法上extends了context,其本质上是一个context,但同时其实现了许多interface,扩充了context的功能,扩充之后的类成为activity或者service。

第二:context本质上包含了场景的所有元素,故而设定其为abstract,activity和service继承自context,它们本质上可以认为就是context。

3、context继承关系图

4、application对象的contextimpl对象创建过程。

step 1、ams通过远程binder调用activitythread的内部类applicationthread的bingapplication方法,参数包括applicationinfo,这个对象由ams创建,通过ipc传递到activitythread的内部类applicationthread中。

public final void bindapplication(string processname, 
        applicationinfo appinfo, list<providerinfo> providers, 
        componentname instrumentationname, string profilefile, 
        parcelfiledescriptor profilefd, boolean autostopprofiler, 
        bundle instrumentationargs, iinstrumentationwatcher instrumentationwatcher, 
        int debugmode, boolean isrestrictedbackupmode, boolean persistent, 
        configuration config, compatibilityinfo compatinfo, 
        map<string, ibinder> services, bundle coresettings) { 
 
      if (services != null) { 
        // setup the service cache in the servicemanager 
        servicemanager.initservicecache(services); 
      } 
 
      setcoresettings(coresettings); 
 
      appbinddata data = new appbinddata(); 
      data.processname = processname; 
      data.appinfo = appinfo; 
      data.providers = providers; 
      data.instrumentationname = instrumentationname; 
      data.instrumentationargs = instrumentationargs; 
      data.instrumentationwatcher = instrumentationwatcher; 
      data.debugmode = debugmode; 
      data.restrictedbackupmode = isrestrictedbackupmode; 
      data.persistent = persistent; 
      data.config = config; 
      data.compatinfo = compatinfo; 
      data.initprofilefile = profilefile; 
      data.initprofilefd = profilefd; 
      data.initautostopprofiler = false; 
      queueorsendmessage(h.bind_application, data); 
    } 

step 2、构建appbinddata对象,如上代码所示。

step 3、调用h handler,执行handlebindapplication()方法。

static final class appbinddata { 
    loadedapk info; 
    string processname; 
    applicationinfo appinfo; 
    list<providerinfo> providers; 
    componentname instrumentationname; 
    bundle instrumentationargs; 
    iinstrumentationwatcher instrumentationwatcher; 
    int debugmode; 
    boolean restrictedbackupmode; 
    boolean persistent; 
    configuration config; 
    compatibilityinfo compatinfo; 
 
    /** initial values for {@link profiler}. */ 
    string initprofilefile; 
    parcelfiledescriptor initprofilefd; 
    boolean initautostopprofiler; 
 
    public string tostring() { 
      return "appbinddata{appinfo=" + appinfo + "}"; 
    } 
  } 
   
  private void handlebindapplication(appbinddata data) { 
    mboundapplication = data; 
    mconfiguration = new configuration(data.config); 
    mcompatconfiguration = new configuration(data.config); 
 
    //.......... 
    timezone.setdefault(null); 
 
    /* 
     * initialize the default locale in this process for the reasons we set the time zone. 
     */ 
    locale.setdefault(data.config.locale); 
 
    data.info = getpackageinfonocheck(data.appinfo, data.compatinfo);//data.info对象为loadapk,此时data.info为null,使用getpackageinfonocheck创建此对象。 
 
    if (data.instrumentationname != null) {//该条件尽在android unit test工程时会执行到,此处直接看else语句 
      contextimpl appcontext = new contextimpl(); 
      appcontext.init(data.info, null, this); 
      instrumentationinfo ii = null; 
      try { 
        ii = appcontext.getpackagemanager(). 
          getinstrumentationinfo(data.instrumentationname, 0); 
      } catch (packagemanager.namenotfoundexception e) { 
      } 
      if (ii == null) { 
        throw new runtimeexception( 
          "unable to find instrumentation info for: " 
          + data.instrumentationname); 
      } 
 
      minstrumentationappdir = ii.sourcedir; 
      minstrumentationapppackage = ii.packagename; 
      minstrumentedappdir = data.info.getappdir(); 
 
      applicationinfo instrapp = new applicationinfo(); 
      instrapp.packagename = ii.packagename; 
      instrapp.sourcedir = ii.sourcedir; 
      instrapp.publicsourcedir = ii.publicsourcedir; 
      instrapp.datadir = ii.datadir; 
      instrapp.nativelibrarydir = ii.nativelibrarydir; 
      loadedapk pi = getpackageinfo(instrapp, data.compatinfo, 
          appcontext.getclassloader(), false, true); 
      contextimpl instrcontext = new contextimpl(); 
      instrcontext.init(pi, null, this); 
 
      try { 
        java.lang.classloader cl = instrcontext.getclassloader(); 
        minstrumentation = (instrumentation) 
          cl.loadclass(data.instrumentationname.getclassname()).newinstance(); 
      } catch (exception e) { 
        throw new runtimeexception( 
          "unable to instantiate instrumentation " 
          + data.instrumentationname + ": " + e.tostring(), e); 
      } 
 
      minstrumentation.init(this, instrcontext, appcontext, 
          new componentname(ii.packagename, ii.name), data.instrumentationwatcher); 
 
      if (mprofiler.profilefile != null && !ii.handleprofiling 
          && mprofiler.profilefd == null) { 
        mprofiler.handlingprofiling = true; 
        file file = new file(mprofiler.profilefile); 
        file.getparentfile().mkdirs(); 
        debug.startmethodtracing(file.tostring(), 8 * 1024 * 1024); 
      } 
 
      try { 
        minstrumentation.oncreate(data.instrumentationargs); 
      } 
      catch (exception e) { 
        throw new runtimeexception( 
          "exception thrown in oncreate() of " 
          + data.instrumentationname + ": " + e.tostring(), e); 
      } 
 
    } else { 
      minstrumentation = new instrumentation();//初始化instrumentation对象,一个应用程序对应一个instrumentation对象 
    } 
 
    application app = data.info.makeapplication(data.restrictedbackupmode, null); 
    minitialapplication = app; 
 
    try { 
      minstrumentation.callapplicationoncreate(app);//调用application程序都应的oncreate方法。 
    } catch (exception e) { 
      if (!minstrumentation.onexception(app, e)) { 
        throw new runtimeexception( 
          "unable to create application " + app.getclass().getname() 
          + ": " + e.tostring(), e); 
      } 
    } 
  }

第三步可以又可以分为三小步。

step 3.1、给appbinddata的info变量赋值。

data.info = getpackageinfonocheck(data.appinfo, data.compatinfo);//data.info对象为loadapk,此时data.info为null,使用getpackageinfonocheck创建此对象。

step 3.2、初始化instrumentation对象。

minstrumentation = new instrumentation();//初始化instrumentation对象,一个应用程序对应一个instrumentation对象 

step 3.3、创建application对象。

application app = data.info.makeapplication(data.restrictedbackupmode, null);

我们着重看一下step 3.1和step3.3.

step 3.1:mpackages和mresourcepackages集合,以packagename为key值,我们知道一个应用程序中的packagename是相同的,也就是说,此处一旦创建,其他地方再次调用此函数,就不需要创建了。总结:也就是说一个应用程序中的loadedapk对象是唯一的。此处的loadedapk,也被称为packageinfo。

public final loadedapk getpackageinfonocheck(applicationinfo ai, 
      compatibilityinfo compatinfo) { 
    return getpackageinfo(ai, compatinfo, null, false, true); 
  } 
  private loadedapk getpackageinfo(applicationinfo ainfo, compatibilityinfo compatinfo, 
      classloader baseloader, boolean securityviolation, boolean includecode) {/*includecode 默认为true*/ 
    synchronized (mpackages) { 
      weakreference<loadedapk> ref; 
      if (includecode) {//1、首先从mpackages或者mresourcepackages 集合中以packagename为key值,获取loadapk对象。 
        ref = mpackages.get(ainfo.packagename); 
      } else { 
        ref = mresourcepackages.get(ainfo.packagename); 
      } 
      loadedapk packageinfo = ref != null ? ref.get() : null; 
      if (packageinfo == null || (packageinfo.mresources != null 
          && !packageinfo.mresources.getassets().isuptodate())) { 
        if (locallogv) slog.v(tag, (includecode ? "loading code package " 
            : "loading resource-only package ") + ainfo.packagename 
            + " (in " + (mboundapplication != null 
                ? mboundapplication.processname : null) 
            + ")"); 
        packageinfo = 
          new loadedapk(this, ainfo, compatinfo, this, baseloader, 
              securityviolation, includecode && 
              (ainfo.flags&applicationinfo.flag_has_code) != 0);//2、如果packageinfo对象为null,则new初始化此对象 
        if (includecode) {//3、最后将创建的此packageinfo对象,加入到mpackages或者mresourcepackages集合中。 
          mpackages.put(ainfo.packagename, 
              new weakreference<loadedapk>(packageinfo)); 
        } else { 
          mresourcepackages.put(ainfo.packagename, 
              new weakreference<loadedapk>(packageinfo)); 
        } 
      } 
      return packageinfo; 
    } 
  }

step 3.3、总结:每个应用程序都存在一个application,用户可以在androidmanifest中重写它,如果不重写也存在一个默认的application对象。

framework/base/core/java/android/app/loadedapk.java

public application makeapplication(boolean forcedefaultappclass, 
    instrumentation instrumentation) { 
  if (mapplication != null) { 
    return mapplication; 
  } 
 
  application app = null; 
 
  string appclass = mapplicationinfo.classname; 
  if (forcedefaultappclass || (appclass == null)) { 
    appclass = "android.app.application";//1、每个工程都存在一个application对象,默认的application对象为android.app.application,客户端可以重写 
  } 
 
  try { 
    java.lang.classloader cl = getclassloader(); 
    contextimpl appcontext = new contextimpl();//2、创建contextimpl对象,这才是context的实际实现类 
    appcontext.init(this, null, mactivitythread);//3、执行contextimpl对象的init方法,initresource等对象 
    app = mactivitythread.minstrumentation.newapplication(//4、以appcontext为参数得到application对象。 
        cl, appclass, appcontext); 
    appcontext.setoutercontext(app); 
  } catch (exception e) { 
    if (!mactivitythread.minstrumentation.onexception(app, e)) { 
      throw new runtimeexception( 
        "unable to instantiate application " + appclass 
        + ": " + e.tostring(), e); 
    } 
  } 
  mactivitythread.mallapplications.add(app);//5、将创建的application对象,加入到a来了application中。 
  mapplication = app; 
 
  if (instrumentation != null) {//6、此时的instrumentation为null。 
    try { 
      instrumentation.callapplicationoncreate(app); 
    } catch (exception e) { 
      if (!instrumentation.onexception(app, e)) { 
        throw new runtimeexception( 
          "unable to create application " + app.getclass().getname() 
          + ": " + e.tostring(), e); 
      } 
    } 
  } 
   
  return app; 
}

5、activity中context的创建过程

step 1、ams通过远程binder调用activitythread的application的schedulelaunchactivity方法,参数包括activityinfo,这个对象由ams创建,通过ipc传递到activitythread的内部类applicationthread中。

public final void schedulelaunchactivity(intent intent, ibinder token, int ident, 
        activityinfo info, configuration curconfig, compatibilityinfo compatinfo, 
        bundle state, list<resultinfo> pendingresults, 
        list<intent> pendingnewintents, boolean notresumed, boolean isforward, 
        string profilename, parcelfiledescriptor profilefd, boolean autostopprofiler) { 
      activityclientrecord r = new activityclientrecord(); 
 
      r.token = token; 
      r.ident = ident; 
      r.intent = intent; 
      r.activityinfo = info; 
      r.compatinfo = compatinfo; 
      r.state = state; 
 
      r.pendingresults = pendingresults; 
      r.pendingintents = pendingnewintents; 
 
      r.startsnotresumed = notresumed; 
      r.isforward = isforward; 
 
      r.profilefile = profilename; 
      r.profilefd = profilefd; 
      r.autostopprofiler = autostopprofiler; 
 
      updatependingconfiguration(curconfig); 
 
      queueorsendmessage(h.launch_activity, r); 
    }

step 2、构建activityclientrecord对象,如上代码所示。

step 3、调用h handler,执行handlelaunchactivity()方法。

其中step 3,又可分为10小步。

private activity performlaunchactivity(activityclientrecord r, intent customintent) { 
    // system.out.println("##### [" + system.currenttimemillis() + "] activitythread.performlaunchactivity(" + r + ")"); 
 
    activityinfo ainfo = r.activityinfo; 
    if (r.packageinfo == null) {//1、如果packageinfo为null,则调用getpackageinfo的得到loadedapk 
      r.packageinfo = getpackageinfo(ainfo.applicationinfo, r.compatinfo, 
          context.context_include_code); 
    } 
 
    componentname component = r.intent.getcomponent(); 
    if (component == null) { 
      component = r.intent.resolveactivity( 
        minitialapplication.getpackagemanager()); 
      r.intent.setcomponent(component); 
    } 
 
    if (r.activityinfo.targetactivity != null) { 
      component = new componentname(r.activityinfo.packagename, 
          r.activityinfo.targetactivity); 
    } 
 
    activity activity = null; 
    try {//2、调用minstrumentation的newactivity方法,得到activity对象 
      java.lang.classloader cl = r.packageinfo.getclassloader(); 
      activity = minstrumentation.newactivity( 
          cl, component.getclassname(), r.intent); 
      strictmode.incrementexpectedactivitycount(activity.getclass()); 
      r.intent.setextrasclassloader(cl); 
      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);//3、获取application对象 
 
      if (locallogv) slog.v(tag, "performing launch of " + r); 
      if (locallogv) slog.v( 
          tag, r + ": app=" + app 
          + ", appname=" + app.getpackagename() 
          + ", pkg=" + r.packageinfo.getpackagename() 
          + ", comp=" + r.intent.getcomponent().toshortstring() 
          + ", dir=" + r.packageinfo.getappdir()); 
 
      if (activity != null) {//4、创建contextimpl对象 
        contextimpl appcontext = new contextimpl(); 
        appcontext.init(r.packageinfo, r.token, this); 
        appcontext.setoutercontext(activity); 
        charsequence title = r.activityinfo.loadlabel(appcontext.getpackagemanager()); 
        configuration config = new configuration(mcompatconfiguration); 
        if (debug_configuration) slog.v(tag, "launching activity " 
            + r.activityinfo.name + " with config " + config); 
        activity.attach(appcontext, this, getinstrumentation(), r.token, 
            r.ident, app, r.intent, r.activityinfo, title, r.parent, 
            r.embeddedid, r.lastnonconfigurationinstances, config);//5、执行activity的attach方法,将此contextimpl对象,设置给activity,activity会调用attachbasecontext 
 
        if (customintent != null) { 
          activity.mintent = customintent; 
        } 
        r.lastnonconfigurationinstances = null; 
        activity.mstartedactivity = false; 
        int theme = r.activityinfo.getthemeresource();//6、设置主题 
        if (theme != 0) { 
          activity.settheme(theme); 
        } 
 
        activity.mcalled = false; 
        minstrumentation.callactivityoncreate(activity, r.state);//7、执行activity的oncreate方法 
        if (!activity.mcalled) { 
          throw new supernotcalledexception( 
            "activity " + r.intent.getcomponent().toshortstring() + 
            " did not call through to super.oncreate()"); 
        } 
        r.activity = activity; 
        r.stopped = true; 
        if (!r.activity.mfinished) { 
          activity.performstart();//8、执行activity的onstart方法 
          r.stopped = false; 
        } 
        if (!r.activity.mfinished) { 
          if (r.state != null) { 
            minstrumentation.callactivityonrestoreinstancestate(activity, r.state);//9、质细腻感onrestoresinstancestate方法 
          } 
        } 
        if (!r.activity.mfinished) { 
          activity.mcalled = false; 
          minstrumentation.callactivityonpostcreate(activity, r.state); 
          if (!activity.mcalled) { 
            throw new supernotcalledexception( 
              "activity " + r.intent.getcomponent().toshortstring() + 
              " did not call through to super.onpostcreate()"); 
          } 
        } 
      } 
      r.paused = true; 
 
      mactivities.put(r.token, r);//10、将包含activity信息集的r对象,也就是activityclientrecord,加入到mactivities中,r.token为key值。 
 
    } 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; 
  }

总结:activity的packageinfo对象和application的packageinfo是同一个对象。

6、service中context的创建过程

step 1、ams通过远程binder调用activitythread的内部类applicationthread的schedulecreateservice方法,参数包括serviceinfo,这个对象由ams创建,通过ipc传递到activitythread的内部类applicationthread中。

public final void schedulecreateservice(ibinder token, 
        serviceinfo info, compatibilityinfo compatinfo) { 
      createservicedata s = new createservicedata(); 
      s.token = token; 
      s.info = info; 
      s.compatinfo = compatinfo; 
 
      queueorsendmessage(h.create_service, s); 
    }

step 2、构建createservicedata对象,如上代码所示。

step 3、调用h handler,执行handlecreateservice()方法。

其中step 3又可分为一下5步。

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);//1、得到packageinfo,调用getpackageinfonocheck 
    service service = null; 
    try { 
      java.lang.classloader cl = packageinfo.getclassloader(); 
      service = (service) cl.loadclass(data.info.name).newinstance(); 
    } catch (exception e) { 
      if (!minstrumentation.onexception(service, e)) { 
        throw new runtimeexception( 
          "unable to instantiate service " + data.info.name 
          + ": " + e.tostring(), e); 
      } 
    } 
 
    try { 
      if (locallogv) slog.v(tag, "creating service " + data.info.name); 
 
      contextimpl context = new contextimpl();//2、创建contextimpl对象 
      context.init(packageinfo, null, this); 
 
      application app = packageinfo.makeapplication(false, minstrumentation);//3、得到application对象 
      context.setoutercontext(service); 
      service.attach(context, this, data.info.name, data.token, app, 
          activitymanagernative.getdefault());//4、调用service的attach方法,将实例化的contextimpl设置给service 
      service.oncreate(); 
      mservices.put(data.token, service);//5、将service对象加入到mservice集合中,key值为data.token。 
      try { 
        activitymanagernative.getdefault().servicedoneexecuting( 
            data.token, 0, 0, 0); 
      } catch (remoteexception e) { 
        // nothing to do. 
      } 
    } catch (exception e) { 
      if (!minstrumentation.onexception(service, e)) { 
        throw new runtimeexception( 
          "unable to create service " + data.info.name 
          + ": " + e.tostring(), e); 
      } 
    } 
  }

综上所述:

1、无论是application还是activity、service,他们的loadedapk对象都是同一个,或者说packageinfo为同一个对象。

2、在创建contextimpl对象时,application和service通过getpackageinfonocheck方法,activity通过getpackageinfo方法得到。

3、一个应用程序中context的个数 = activity的数量+service的数量 +1。这里的1代表application。

4、应用程序中包含着多个contextimpl对象,其内部的packageinfo却是同一个。这样设计意味着contextimpl是一个轻量级类,packageinfo是一个重量级类,所有和包相关的操作封装到packageinfo中,有利于代码的封装与隐藏。

class contextimpl extends context { 
  private final static string tag = "applicationcontext"; 
  private final static boolean debug = false; 
 
  private static final hashmap<string, sharedpreferencesimpl> ssharedprefs = 
      new hashmap<string, sharedpreferencesimpl>(); 
 
  /*package*/ loadedapk mpackageinfo;

以上就是本篇文章的全部内容,希望大家通过学习能够对context有更深入的理解。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网