<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      安卓筆記俠

      專注安卓開發

      導航

      Android深入理解Context(一)Context關聯類和Application Context創建過程

      前言

      Context也就是上下文對象,是Android較為常用的類,但是對于Context,很多人都停留在會用的階段,這個系列會帶大家從源碼角度來分析Context,從而更加深入的理解它。

      1.Context概述

      Context意為上下文或者場景,是一個應用程序環境信息的接口。
      在開發中我們經常會使用Context,它的使用場景總的來說分為兩大類,它們分別是:

      • 使用Context調用方法,比如:啟動Activity、訪問資源、調用系統級服務等。
      • 調用方法時傳入Context,比如:彈出Toast、創建Dialog等。

      Activity、Service和Application都是間接的繼承自Context的,因此,我們可以計算出一個應用程序進程中有多少個Context,這個數量等于Activity和Service的總個數加1,1指的是Application的數量。

      Context是一個抽象類,它的內部定義了很多方法以及靜態常量,它的具體實現類為ContextImpl。和Context相關聯的類,除了ContextImpl還有ContextWrapper、ContextThemeWrapper和Activity等等,下面給出Context的關系圖。

      從圖中我們可以看出,ContextImpl和ContextWrapper繼承自Context,ContextWrapper內部包含有Context類型的mBase對象,mBase具體指向的是ContextImpl。ContextImpl提供了很多功能,但是外界需要使用并拓展ContextImpl的功能,因此設計上使用了裝飾模式,ContextWrapper是裝飾類,它對ContextImpl進行包裝,ContextWrapper主要是起了方法傳遞作用,ContextWrapper中幾乎所有的方法實現都是調用ContextImpl的相應方法來實現的。
      ContextThemeWrapper、Service和Application都繼承自ContextWrapper,這樣他們都可以通過mBase來使用Context的方法,同時它們也是裝飾類,在ContextWrapper的基礎上又添加了不同的功能。
      ContextThemeWrapper中包含和主題相關的方法(比如: getTheme方法),因此,需要主題的Activity繼承ContextThemeWrapper,而不需要主題的Service則繼承ContextWrapper。

      2.Application Context的創建過程

      我們通過調用getApplicationContext來獲取應用程序的全局的Application Context,那么Application Context是如何創建的呢?
      當一個應用程序啟動完成后,應用程序就會有一個全局的Application Context。那么我們就從應用程序啟動過程開始著手。

      Android深入四大組件(一)應用程序啟動過程(后篇)這篇文章的最后講了ActivityThread啟動Activity。ActivityThread作為應用程序進程的核心類,它會調用它的內部類ApplicationThread的scheduleLaunchActivity方法來啟動Activity,如下所示。

      frameworks/base/core/java/android/app/ActivityThread.java

      private class ApplicationThread extends ApplicationThreadNative {
       ...
         @Override
          public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                  ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                  CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                  int procState, Bundle state, PersistableBundle persistentState,
                  List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                  boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
                  updateProcessState(procState, false);
                  ActivityClientRecord r = new ActivityClientRecord();
                  ...
                  sendMessage(H.LAUNCH_ACTIVITY, r);
          }
       ...   
      }
      View Code

      在ApplicationThread的scheduleLaunchActivity方法中向H類發送LAUNCH_ACTIVITY類型的消息,目的是將啟動Activity的邏輯放在主線程中的消息隊列中,這樣啟動Activity的邏輯會在主線程中執行。我們接著查看H類的handleMessage方法對LAUNCH_ACTIVITY類型的消息的處理。

      frameworks/base/core/java/android/app/ActivityThread.java

      private class H extends Handler {
            public static final int LAUNCH_ACTIVITY         = 100;
      ...
      public void handleMessage(Message msg) {
                if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
                switch (msg.what) {
                    case LAUNCH_ACTIVITY: {
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                        final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                        r.packageInfo = getPackageInfoNoCheck(
                                r.activityInfo.applicationInfo, r.compatInfo);//1
                        handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");//2
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    } break;
                  
                  ...
      }
      View Code

      H繼承自Handler ,是ActivityThread的內部類。在注釋1處通過getPackageInfoNoCheck方法獲得LoadedApk類型的對象,并將該對象賦值給ActivityClientRecord 的成員變量packageInfo,其中LoadedApk用來描述已加載的APK文件。在注釋2處調用handleLaunchActivity方法,如下所示。
      frameworks/base/core/java/android/app/ActivityThread.java

      private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
          ...
           Activity a = performLaunchActivity(r, customIntent);
          ...
       }
      View Code

      我們接著查看performLaunchActivity方法:
      frameworks/base/core/java/android/app/ActivityThread.java

      private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
      ...
          try {
              Application app = r.packageInfo.makeApplication(false, mInstrumentation);
             ...
          } 
          ...
          return activity;
      }
      View Code

      performLaunchActivity方法中有很多重要的邏輯,這里只保留了Application Context相關的邏輯,想要更多了解performLaunchActivity方法中的邏輯請查看Android深入四大組件(一)應用程序啟動過程(后篇)這篇文章的第二小節。這里ActivityClientRecord 的成員變量packageInfo是LoadedApk類型的,我們接著來查看LoadedApk的makeApplication方法,如下所示。
      frameworks/base/core/java/android/app/LoadedApk.java

      public Application makeApplication(boolean forceDefaultAppClass,
              Instrumentation instrumentation) {
          if (mApplication != null) {//1
              return mApplication;
          }
          ...
          try {
            ...
             java.lang.ClassLoader cl = getClassLoader();
            ...
              ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);//2
              app = mActivityThread.mInstrumentation.newApplication(
                      cl, appClass, appContext);//3
              appContext.setOuterContext(app);//4
          } catch (Exception e) {
             ...
          }
          mActivityThread.mAllApplications.add(app);
          mApplication = app;//5
          ...
          return app;
      }
      View Code

      注釋1處如果mApplication不為null則返回mApplication,這里假設是第一次啟動應用程序,因此mApplication為null。在注釋2處通過ContextImpl的createAppContext方法來創建ContextImpl。注釋3處的代碼用來創建Application,在Instrumentation的newApplication方法中傳入了ClassLoader類型的對象以及注釋2處創建的ContextImpl 。在注釋4處將Application賦值給ContextImpl的Context類型的成員變量mOuterContext。注釋5處將Application賦值給LoadedApk的成員變量mApplication,在Application Context的獲取過程中我們會再次用到mApplication。我們來查看注釋3處的Application是如何創建的,Instrumentation的newApplication方法如下所示。
      frameworks/base/core/java/android/app/Instrumentation.java

      static public Application newApplication(Class<?> clazz, Context context)
              throws InstantiationException, IllegalAccessException, 
              ClassNotFoundException {
          Application app = (Application)clazz.newInstance();//1
          app.attach(context);
          return app;
      }
      View Code

      Instrumentation中有兩個newApplication重載方法,最終會調用上面這個重載方法。注釋1處通過反射來創建Application,并調用了Application的attach方法,并將ContextImpl傳進去:
      frameworks/base/core/java/android/app/Application.java

      /* package */ final void attach(Context context) {
          attachBaseContext(context);
          mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
      }
      View Code

      attach方法中調用了attachBaseContext方法,它的實現在Application的父類ContextWrapper中,代碼如下所示。
      frameworks/base/core/java/android/content/ContextWrapper.java

      protected void attachBaseContext(Context base) {
           if (mBase != null) {
               throw new IllegalStateException("Base context already set");
           }
           mBase = base;
       }
      View Code

      從上文我們得知,這個base指的是ContextImpl,將ContextImpl賦值給ContextWrapper的Context類型的成員變量mBase。Application Context的創建過程就講到這里,最后給出Application Context創建過程的時序圖。
      繪圖1_副本.png繪圖1_副本.png

      3.Application Context的獲取過程

      當我們熟知了Application Context的創建過程,那么它的獲取過程會非常好理解。我們通過調用getApplicationContext方法來獲得Application Context,getApplicationContext方法的實現在ContextWrapper中,如下所示。
      frameworks/base/core/java/android/content/ContextWrapper.java

      @Override
      public Context getApplicationContext() {
          return mBase.getApplicationContext();
      }
      View Code

      從上文我們得知,mBase指的是ContextImpl,我們來查看 ContextImpl的getApplicationContext方法:
      frameworks/base/core/java/android/app/ContextImpl.java

      @Override
      public Context getApplicationContext() {
          return (mPackageInfo != null) ?
                  mPackageInfo.getApplication() : mMainThread.getApplication();
      }
      View Code

      如果LoadedApk不為null,則調用LoadedApk的getApplication方法,否則調用AvtivityThread的getApplication方法。由于應用程序這時已經啟動,因此LoadedApk不會為null,則會調用LoadedApk的getApplication方法:
      frameworks/base/core/java/android/app/LoadedApk.java

      Application getApplication() {
           return mApplication;
       }
      View Code

      這里的mApplication我們應該很熟悉,它在上文LoadedApk的makeApplication方法的注釋5處被賦值。這樣我們通過getApplicationContext方法就獲取到了Application Context。

      posted on 2016-10-19 20:21  安卓筆記俠  閱讀(2041)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 91午夜福利一区二区三区| 丰满岳乱妇久久久| 人妻va精品va欧美va| 亚洲AV永久无码嘿嘿嘿嘿| 国内自拍视频一区二区三区| 国产亚洲精品AA片在线爽| 特黄aaaaaaaaa毛片免费视频| 日本xxxx色视频在线播放| 亚洲一区二区偷拍精品| 亚洲精品蜜桃久久久久久| 视频免费完整版在线播放| 久久天天躁夜夜躁狠狠85| 无码日韩精品一区二区三区免费| 性做久久久久久久| 免费看欧美日韩一区二区三区| 四虎精品视频永久免费| 国产欧美精品一区aⅴ影院| 与子乱对白在线播放单亲国产| 在线一区二区中文字幕| 亚洲av成人无网码天堂| 99久久精品费精品国产一区二| 国产成人精品1024免费下载| 日本久久99成人网站| 国产91丝袜在线播放动漫| 影音先锋女人AA鲁色资源| 精品人妻中文无码av在线 | 国产精品成人av在线观看春天| 国产精品一二区在线观看| 国产精品自拍午夜福利| 荣成市| av在线播放日韩亚洲欧| 成人3D动漫一区二区三区| 精品国产亚洲一区二区三区在线观看| 阿拉善盟| 欧美成人黄在线观看| 日韩免费视频一一二区| 亚洲欧洲日韩精品在线| 国产伦一区二区三区久久| 亚洲熟妇在线视频观看| 久久月本道色综合久久| 亚洲av色香蕉一区二区三|