Android中Context詳解 ---- 你所不知道的Context

本文原創 ,轉載必須註明出處 :http://blog.csdn.net/qinjuningjava

 

 

             前言:本文是我讀《Android內核剖析》第7章 後造成的讀書筆記 ,在此向欲瞭解Android框架的書籍推薦此書。android

 

 

 

 

        你們好,  今天給你們介紹下咱們在應用開發中最熟悉而陌生的朋友-----Context類 ,說它熟悉,是應爲咱們在開發中app

   時刻的在與它打交道,例如:Service、BroadcastReceiver、Activity等都會利用到Context的相關方法 ; 說它陌生,徹底是框架

   由於咱們真正的不懂Context的原理、類結構關係。一個簡單的問題是,一個應用程序App中存在多少個Context實例對象呢?ide

   一個、兩個? 在此先賣個關子吧。讀了本文,相信您會豁然開朗的 。函數

 

      Context,中文直譯爲「上下文」,SDK中對其說明以下:學習

         Interface to global information about an application environment. This is an abstract class whose implementationthis

  is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls spa

  for application-level operations such as launching activities, broadcasting and receiving intents, etc.net

 

    從上可知一下三點,即:

        一、它描述的是一個應用程序環境的信息,即上下文。

        二、該類是一個抽象(abstract class)類,Android提供了該抽象類的具體實現類(後面咱們會講到是ContextIml類)。

        三、經過它咱們能夠獲取應用程序的資源和類,也包括一些應用級別操做,例如:啓動一個Activity,發送廣播,接受Intent

      信息 等。。

 

 

   因而,咱們能夠利用該Context對象去構建應用級別操做(application-level operations) 。

 

 1、Context相關類的繼承關係

 

                         

 

  相關類介紹:

 

   Context類    路徑: /frameworks/base/core/java/android/content/Context.java

            說明:  抽象類,提供了一組通用的API。

      源代碼(部分)以下:   

[java] view plaincopyprint?

  1. public abstract class Context {  

  2.      ...  

  3.      public abstract Object getSystemService(String name);  //得到系統級服務  

  4.      public abstract void startActivity(Intent intent);     //經過一個Intent啓動Activity  

  5.      public abstract ComponentName startService(Intent service);  //啓動Service  

  6.      //根據文件名獲得SharedPreferences對象  

  7.      public abstract SharedPreferences getSharedPreferences(String name,int mode);  

  8.      ...  

  9. }  

 

  ContextIml.java類  路徑 :/frameworks/base/core/java/android/app/ContextImpl.java

          說明:該Context類的實現類爲ContextIml,該類實現了Context類的功能。請注意,該函數的大部分功能都是直接調用

      其屬性mPackageInfo去完成,這點咱們後面會講到。    

         源代碼(部分)以下:

[java] view plaincopyprint?

  1. /** 

  2.  * Common implementation of Context API, which provides the base 

  3.  * context object for Activity and other application components. 

  4.  */  

  5. class ContextImpl extends Context{  

  6.     //全部Application程序公用一個mPackageInfo對象  

  7.     /*package*/ ActivityThread.PackageInfo mPackageInfo;  

  8.       

  9.     @Override  

  10.     public Object getSystemService(String name){  

  11.         ...  

  12.         else if (ACTIVITY_SERVICE.equals(name)) {  

  13.             return getActivityManager();  

  14.         }   

  15.         else if (INPUT_METHOD_SERVICE.equals(name)) {  

  16.             return InputMethodManager.getInstance(this);  

  17.         }  

  18.     }   

  19.     @Override  

  20.     public void startActivity(Intent intent) {  

  21.         ...  

  22.         //開始啓動一個Activity  

  23.         mMainThread.getInstrumentation().execStartActivity(  

  24.             getOuterContext(), mMainThread.getApplicationThread(), nullnull, intent, -1);  

  25.     }  

  26. }  

 


 

  ContextWrapper類 路徑 :\frameworks\base\core\java\android\content\ContextWrapper.java

        說明: 正如其名稱同樣,該類只是對Context類的一種包裝,該類的構造函數包含了一個真正的Context引用,即ContextIml

       對象。    源代碼(部分)以下:

[java] view plaincopyprint?

  1. public class ContextWrapper extends Context {  

  2.     Context mBase;  //該屬性指向一個ContextIml實例,通常在建立Application、Service、Activity時賦值  

  3.       

  4.     //建立Application、Service、Activity,會調用該方法給mBase屬性賦值  

  5.     protected void attachBaseContext(Context base) {  

  6.         if (mBase != null) {  

  7.             throw new IllegalStateException("Base context already set");  

  8.         }  

  9.         mBase = base;  

  10.     }  

  11.     @Override  

  12.     public void startActivity(Intent intent) {  

  13.         mBase.startActivity(intent);  //調用mBase實例方法  

  14.     }  

  15. }  

 


 

   ContextThemeWrapper類 路徑:/frameworks/base/core/java/android/view/ContextThemeWrapper.java

      說明:該類內部包含了主題(Theme)相關的接口,即android:theme屬性指定的。只有Activity須要主題,Service不須要主題,

   因此Service直接繼承於ContextWrapper類。

      源代碼(部分)以下:

[java] view plaincopyprint?

  1. public class ContextThemeWrapper extends ContextWrapper {  

  2.      //該屬性指向一個ContextIml實例,通常在建立Application、Service、Activity時賦值  

  3.        

  4.      private Context mBase;  

  5.     //mBase賦值方式一樣有一下兩種  

  6.      public ContextThemeWrapper(Context base, int themeres) {  

  7.             super(base);  

  8.             mBase = base;  

  9.             mThemeResource = themeres;  

  10.      }  

  11.   

  12.      @Override  

  13.      protected void attachBaseContext(Context newBase) {  

  14.             super.attachBaseContext(newBase);  

  15.             mBase = newBase;  

  16.      }  

  17. }  

 

 

     Activity類 、Service類 、Application類本質上都是Context子類, 更多信息你們能夠自行參考源代碼進行理解。

 

 

2、 何時建立Context實例 

 

      熟悉了Context的繼承關係後,咱們接下來分析應用程序在什麼狀況須要建立Context對象的?應用程序建立Context實例的

 狀況有以下幾種狀況:

      一、建立Application 對象時, 並且整個App共一個Application對象

      二、建立Service對象時

      三、建立Activity對象時

 

    所以應用程序App共有的Context數目公式爲:

 

                     總Context實例個數 = Service個數 + Activity個數 + 1(Application對應的Context實例)

 

  具體建立Context的時機

 

     一、建立Application對象的時機

 

       每一個應用程序在第一次啓動時,都會首先建立Application對象。若是對應用程序啓動一個Activity(startActivity)流程比較

清楚的話,建立Application的時機在建立handleBindApplication()方法中,該函數位於 ActivityThread.java類中 ,以下:

[java] view plaincopyprint?

  1. //建立Application時同時建立的ContextIml實例  

  2. private final void handleBindApplication(AppBindData data){  

  3.     ...  

  4.     ///建立Application對象  

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

  6.     ...  

  7. }  

  8.   

  9. public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {  

  10.     ...  

  11.     try {  

  12.         java.lang.ClassLoader cl = getClassLoader();  

  13.         ContextImpl appContext = new ContextImpl();    //建立一個ContextImpl對象實例  

  14.         appContext.init(thisnull, mActivityThread);  //初始化該ContextIml實例的相關屬性  

  15.         ///新建一個Application對象   

  16.         app = mActivityThread.mInstrumentation.newApplication(  

  17.                 cl, appClass, appContext);  

  18.        appContext.setOuterContext(app);  //將該Application實例傳遞給該ContextImpl實例           

  19.     }   

  20.     ...  

  21. }  

 

 

    二、建立Activity對象的時機

 

       經過startActivity()或startActivityForResult()請求啓動一個Activity時,若是系統檢測須要新建一個Activity對象時,就會

  回調handleLaunchActivity()方法,該方法繼而調用performLaunchActivity()方法,去建立一個Activity實例,而且回調

 onCreate(),onStart()方法等, 函數都位於 ActivityThread.java類 ,以下:

[java] view plaincopyprint?

  1. //建立一個Activity實例時同時建立ContextIml實例  

  2. private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {  

  3.     ...  

  4.     Activity a = performLaunchActivity(r, customIntent);  //啓動一個Activity  

  5. }  

  6. private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {  

  7.     ...  

  8.     Activity activity = null;  

  9.     try {  

  10.         //建立一個Activity對象實例  

  11.         java.lang.ClassLoader cl = r.packageInfo.getClassLoader();  

  12.         activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);  

  13.     }  

  14.     if (activity != null) {  

  15.         ContextImpl appContext = new ContextImpl();      //建立一個Activity實例  

  16.         appContext.init(r.packageInfo, r.token, this);   //初始化該ContextIml實例的相關屬性  

  17.         appContext.setOuterContext(activity);            //將該Activity信息傳遞給該ContextImpl實例  

  18.         ...  

  19.     }  

  20.     ...      

  21. }  

 

 

   三、建立Service對象的時機

 

       經過startService或者bindService時,若是系統檢測到須要新建立一個Service實例,就會回調handleCreateService()方法,

 完成相關數據操做。handleCreateService()函數位於 ActivityThread.java類,以下:

[java] view plaincopyprint?

  1. //建立一個Service實例時同時建立ContextIml實例  

  2. private final void handleCreateService(CreateServiceData data){  

  3.     ...  

  4.     //建立一個Service實例  

  5.     Service service = null;  

  6.     try {  

  7.         java.lang.ClassLoader cl = packageInfo.getClassLoader();  

  8.         service = (Service) cl.loadClass(data.info.name).newInstance();  

  9.     } catch (Exception e) {  

  10.     }  

  11.     ...  

  12.     ContextImpl context = new ContextImpl(); //建立一個ContextImpl對象實例  

  13.     context.init(packageInfo, nullthis);   //初始化該ContextIml實例的相關屬性  

  14.     //得到咱們以前建立的Application對象信息  

  15.     Application app = packageInfo.makeApplication(false, mInstrumentation);  

  16.     //將該Service信息傳遞給該ContextImpl實例  

  17.     context.setOuterContext(service);  

  18.     ...  

  19. }  


 

    另外,須要強調一點的是,經過對ContextImp的分析可知,其方法的大多數操做都是直接調用其屬性mPackageInfo(該屬性類

型爲PackageInfo)的相關方法而來。這說明ContextImp是一種輕量級類,而PackageInfo纔是真正重量級的類。而一個App裏的

有ContextIml實例,都對應同一個packageInfo對象。

            

 

     最後給你們分析利用Context獲取SharedPreferences類的使用方法,SharedPreferences類想必你們都使用過,其通常獲取方

法就是經過調用getSharedPreferences()方法去根據相關信息獲取SharedPreferences對象。具體流程以下:

 

    1 、調用  getSharedPreferences()獲取對應的的文件,該函數實現功能以下:

 

[java] view plaincopyprint?

  1. //Context類靜態數據集合,以鍵值對保存了全部讀取該xml文件後所造成的數據集合  

  2. private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs =   

  3.        new HashMap<File, SharedPreferencesImpl>();   

  4.   

  5. @Override  

  6. public SharedPreferences getSharedPreferences(String name, int mode){  

  7.      //其所對應的SharedPreferencesImpl對象 ,該對象已一個HashMap集合保存了咱們對該文件序列化結果  

  8.      SharedPreferencesImpl sp;    

  9.      File f = getSharedPrefsFile(name);  //該包下是否存在對應的文件,不存在就新建一個  

  10.      synchronized (sSharedPrefs) {       //是否已經讀取過該文件,是就直接返回該SharedPreferences對象  

  11.          sp = sSharedPrefs.get(f);  

  12.          if (sp != null && !sp.hasFileChanged()) {  

  13.              //Log.i(TAG, "Returning existing prefs " + name + ": " + sp);  

  14.              return sp;  

  15.          }  

  16.      }  

  17.      //如下爲序列化該xml文件,同時將數據寫到map集合中       

  18.      Map map = null;  

  19.      if (f.exists() && f.canRead()) {  

  20.          try {  

  21.              str = new FileInputStream(f);  

  22.              map = XmlUtils.readMapXml(str);  

  23.              str.close();  

  24.          }   

  25.          ...  

  26.      }  

  27.        

  28.      synchronized (sSharedPrefs) {  

  29.          if (sp != null) {  

  30.              //Log.i(TAG, "Updating existing prefs " + name + " " + sp + ": " + map);  

  31.              sp.replace(map);   //更新數據集合  

  32.          } else {  

  33.              sp = sSharedPrefs.get(f);  

  34.              if (sp == null) {    

  35.                  //新建一個SharedPreferencesImpl對象,而且設置其相關屬性  

  36.                  sp = new SharedPreferencesImpl(f, mode, map);    

  37.                  sSharedPrefs.put(f, sp);  

  38.              }  

  39.          }  

  40.          return sp;  

  41.      }  

  42. }  

 

   二、 SharedPreferences 不過是個接口,它定義了一些操做xml文件的方法,其真正實現類爲SharedPreferencesImpl ,該類是

    ContextIml的內部類,該類以下:

 

[java] view plaincopyprint?

  1. //soga,這種形式咱們在分析Context ContextIml時接觸過   

  2. //SharedPreferences只是一種接口,其真正實現類是SharedPreferencesImpl類  

  3. private static final class SharedPreferencesImpl implements SharedPreferences{  

  4.      private Map mMap;  //保存了該文件序列化結果後的操做, 鍵值對形式  

  5.        

  6.      //經過key值獲取對應的value值  

  7.      public String getString(String key, String defValue) {  

  8.          synchronized (this) {  

  9.              String v = (String)mMap.get(key);  

  10.              return v != null ? v : defValue;  

  11.          }  

  12.      }  

  13.      ...  

  14.      //得到該SharedPreferencesImpl對象對應的Edito類,對數據進行操做  

  15.      public final class EditorImpl implements Editor {  

  16.          private final Map<String, Object> mModified = Maps.newHashMap(); //保存了對鍵值變化的集合  

  17.      }  

  18. }  

 



       基本上獲取SharedPreferences 對象就是這麼來的,關於Context裏的更多方法請你們參照源代碼認真學習吧。

相關文章
相關標籤/搜索