android中Context深入详解

android中Context深入详解,第1张

概述以下分别通过Context认知角度,继承关系,对象创建等方面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,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,true);   }   private LoadedApk getPackageInfo(ApplicationInfo aInfo,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,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,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);       }     }   }      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,Bundle state,List<ResultInfo> pendingResults,List<Intent> pendingNewIntents,boolean notResumed,boolean isForward,String profilename,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,getInstrumentation(),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,this);        Application app = packageInfo.makeApplication(false,mInstrumentation);//3、得到Application对象       context.setouterContext(service);       service.attach(context,data.info.name,data.token,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);       } 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有更深入的理解。

总结

以上是内存溢出为你收集整理的android中Context深入详解全部内容,希望文章能够帮你解决android中Context深入详解所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1143586.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-31
下一篇2022-05-31

发表评论

登录后才能评论

评论列表(0条)

    保存