android中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继承关系图
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有更深入的理解。