欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

android中Context深入详解

程序员文章站 2022-05-15 22:39:56
以下分别通过context认知角度,继承关系,对象创建等方面android中context做了深入的解释,一起学习下。 1、context认知。 context译为场景...

以下分别通过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继承关系图

android中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有更深入的理解。