欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

android中Context深入詳解

 更新時(shí)間:2017年11月27日 09:56:22   投稿:laozhang  
本文主要給大家深入的講解一下android中Context知識(shí)以及繼承關(guān)系,有助于大家更好的理解Context。

以下分別通過Context認(rèn)知角度,繼承關(guān)系,對(duì)象創(chuàng)建等方面android中Context做了深入的解釋,一起學(xué)習(xí)下。

1、Context認(rèn)知。

Context譯為場(chǎng)景,一個(gè)應(yīng)用程序可以認(rèn)為是一個(gè)工作環(huán)境,在這個(gè)工作環(huán)境中可以存在許多場(chǎng)景,coding代碼的場(chǎng)景 ,打電話的場(chǎng)景,開會(huì)的場(chǎng)景。這些場(chǎng)景可以類比不同的Activity,service。

2、從兩個(gè)角度認(rèn)識(shí)Context。

第一:Activity繼承自Context,同時(shí)Activity還實(shí)現(xiàn)了其他的interface,我們可以這樣看,activity在語法上extends了Context,其本質(zhì)上是一個(gè)Context,但同時(shí)其實(shí)現(xiàn)了許多interface,擴(kuò)充了Context的功能,擴(kuò)充之后的類成為Activity或者Service。

第二:Context本質(zhì)上包含了場(chǎng)景的所有元素,故而設(shè)定其為abstract,Activity和Service繼承自Context,它們本質(zhì)上可以認(rèn)為就是Context。

3、Context繼承關(guān)系圖

4、Application對(duì)象的ContextImpl對(duì)象創(chuàng)建過程。

step 1、Ams通過遠(yuǎn)程Binder調(diào)用ActivityThread的內(nèi)部類ApplicationThread的bingApplication方法,參數(shù)包括ApplicationInfo,這個(gè)對(duì)象由Ams創(chuàng)建,通過IPC傳遞到ActivityThread的內(nèi)部類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、構(gòu)建AppBindData對(duì)象,如上代碼所示。

step 3、調(diào)用H Handler,執(zhí)行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對(duì)象為L(zhǎng)oadApk,此時(shí)data.info為null,使用getPackageINfoNoCheck創(chuàng)建此對(duì)象。 
 
    if (data.instrumentationName != null) {//該條件盡在Android Unit Test工程時(shí)會(huì)執(zhí)行到,此處直接看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對(duì)象,一個(gè)應(yīng)用程序?qū)?yīng)一個(gè)Instrumentation對(duì)象 
    } 
 
    Application app = data.info.makeApplication(data.restrictedBackupMode, null); 
    mInitialApplication = app; 
 
    try { 
      mInstrumentation.callApplicationOnCreate(app);//調(diào)用Application程序都應(yīng)的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對(duì)象為L(zhǎng)oadApk,此時(shí)data.info為null,使用getPackageINfoNoCheck創(chuàng)建此對(duì)象。

step 3.2、初始化Instrumentation對(duì)象。

mInstrumentation = new Instrumentation();//初始化Instrumentation對(duì)象,一個(gè)應(yīng)用程序?qū)?yīng)一個(gè)Instrumentation對(duì)象 

step 3.3、創(chuàng)建Application對(duì)象。

Application app = data.info.makeApplication(data.restrictedBackupMode, null);

我們著重看一下step 3.1和step3.3.

step 3.1:mPackages和mResourcePackages集合,以packageName為key值,我們知道一個(gè)應(yīng)用程序中的packageName是相同的,也就是說,此處一旦創(chuàng)建,其他地方再次調(diào)用此函數(shù),就不需要?jiǎng)?chuàng)建了??偨Y(jié):也就是說一個(gè)應(yīng)用程序中的LoadedApk對(duì)象是唯一的。此處的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 默認(rèn)為true*/ 
    synchronized (mPackages) { 
      WeakReference<LoadedApk> ref; 
      if (includeCode) {//1、首先從mPackages或者mResourcePackages 集合中以packageName為Key值,獲取LoadApk對(duì)象。 
        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對(duì)象為null,則new初始化此對(duì)象 
        if (includeCode) {//3、最后將創(chuàng)建的此packageInfo對(duì)象,加入到mPackages或者mResourcePackages集合中。 
          mPackages.put(aInfo.packageName, 
              new WeakReference<LoadedApk>(packageInfo)); 
        } else { 
          mResourcePackages.put(aInfo.packageName, 
              new WeakReference<LoadedApk>(packageInfo)); 
        } 
      } 
      return packageInfo; 
    } 
  }

step 3.3、總結(jié):每個(gè)應(yīng)用程序都存在一個(gè)Application,用戶可以在AndroidManifest中重寫它,如果不重寫也存在一個(gè)默認(rèn)的Application對(duì)象。

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、每個(gè)工程都存在一個(gè)Application對(duì)象,默認(rèn)的Application對(duì)象為android.app.Application,客戶端可以重寫 
  } 
 
  try { 
    java.lang.ClassLoader cl = getClassLoader(); 
    ContextImpl appContext = new ContextImpl();//2、創(chuàng)建ContextImpl對(duì)象,這才是Context的實(shí)際實(shí)現(xiàn)類 
    appContext.init(this, null, mActivityThread);//3、執(zhí)行ContextImpl對(duì)象的init方法,initResource等對(duì)象 
    app = mActivityThread.mInstrumentation.newApplication(//4、以appContext為參數(shù)得到Application對(duì)象。 
        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、將創(chuàng)建的Application對(duì)象,加入到A來了Application中。 
  mApplication = app; 
 
  if (instrumentation != null) {//6、此時(shí)的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的創(chuàng)建過程

step 1、Ams通過遠(yuǎn)程Binder調(diào)用ActivityThread的Application的scheduleLaunchActivity方法,參數(shù)包括ActivityInfo,這個(gè)對(duì)象由Ams創(chuàng)建,通過IPC傳遞到ActivityThread的內(nèi)部類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、構(gòu)建ActivityClientRecord對(duì)象,如上代碼所示。

step 3、調(diào)用H Handler,執(zhí)行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,則調(diào)用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、調(diào)用mInstrumentation的newActivity方法,得到Activity對(duì)象 
      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對(duì)象 
 
      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、創(chuàng)建ContextImpl對(duì)象 
        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、執(zhí)行Activity的attach方法,將此ContextImpl對(duì)象,設(shè)置給Activity,activity會(huì)調(diào)用attachBaseContext 
 
        if (customIntent != null) { 
          activity.mIntent = customIntent; 
        } 
        r.lastNonConfigurationInstances = null; 
        activity.mStartedActivity = false; 
        int theme = r.activityInfo.getThemeResource();//6、設(shè)置主題 
        if (theme != 0) { 
          activity.setTheme(theme); 
        } 
 
        activity.mCalled = false; 
        mInstrumentation.callActivityOnCreate(activity, r.state);//7、執(zhí)行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、執(zhí)行Activity的onStart方法 
          r.stopped = false; 
        } 
        if (!r.activity.mFinished) { 
          if (r.state != null) { 
            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);//9、質(zhì)細(xì)膩感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對(duì)象,也就是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; 
  }

總結(jié):activity的packageInfo對(duì)象和application的packageInfo是同一個(gè)對(duì)象。

6、Service中Context的創(chuàng)建過程

step 1、Ams通過遠(yuǎn)程Binder調(diào)用ActivityThread的內(nèi)部類ApplicationThread的scheduleCreateService方法,參數(shù)包括serviceInfo,這個(gè)對(duì)象由Ams創(chuàng)建,通過IPC傳遞到ActivityThread的內(nèi)部類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、構(gòu)建CreateServiceData對(duì)象,如上代碼所示。

step 3、調(diào)用H Handler,執(zhí)行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,調(diào)用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、創(chuàng)建ContextImpl對(duì)象 
      context.init(packageInfo, null, this); 
 
      Application app = packageInfo.makeApplication(false, mInstrumentation);//3、得到Application對(duì)象 
      context.setOuterContext(service); 
      service.attach(context, this, data.info.name, data.token, app, 
          ActivityManagerNative.getDefault());//4、調(diào)用service的attach方法,將實(shí)例化的ContextImpl設(shè)置給Service 
      service.onCreate(); 
      mServices.put(data.token, service);//5、將service對(duì)象加入到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對(duì)象都是同一個(gè),或者說packageInfo為同一個(gè)對(duì)象。

2、在創(chuàng)建ContextImpl對(duì)象時(shí),Application和SErvice通過getPackageInfoNoCheck方法,Activity通過getPackageInfo方法得到。

3、一個(gè)應(yīng)用程序中Context的個(gè)數(shù) = Activity的數(shù)量+Service的數(shù)量 +1。這里的1代表Application。

4、應(yīng)用程序中包含著多個(gè)ContextImpl對(duì)象,其內(nèi)部的PackageInfo卻是同一個(gè)。這樣設(shè)計(jì)意味著ContextImpl是一個(gè)輕量級(jí)類,PackageInfo是一個(gè)重量級(jí)類,所有和包相關(guān)的操作封裝到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;

以上就是本篇文章的全部?jī)?nèi)容,希望大家通過學(xué)習(xí)能夠?qū)ontext有更深入的理解。

相關(guān)文章

最新評(píng)論