Android Context 原理

来源:互联网 发布:sql server 按照工作日 编辑:程序博客网 时间:2024/05/15 09:59

原文:https://sites.google.com/site/terrylai14/home/android-context-yuan-li

Context,中文可以翻譯成"場景",SDK說明如下:Interface to global information about an application environment. This is an abstract class whose implementationis provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc



由此可知以下三點:

        1、他描述的是一個應用程式的場景

        2、context是一個抽象類別abstract,Android提供了此抽象類別的具體實現(ContextIml)

        3、透過context我們可以取得應用程式的資源,包含一些應用層的操作,像是啟動activity 發送broadcast


先來看看Context的架構吧



架構介紹:

   Context    Path: /frameworks/base/core/java/android/content/Context.java

      說明:  abstract,提供了通用的API。

      部分source code:   

  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  Path :/frameworks/base/core/java/android/app/ContextImpl.java

     說明:這個Context類別的實現為ContextIml,這類別實現了Context類別的功能。這個函数的大部分功能都是直接調用其属性mPackageInfo去完成。    

     部分source code:

  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(), null, null, intent, -1);  
  25.     }  
  26. }  

  ContextWrapper Path :\frameworks\base\core\java\android\content\ContextWrapper.java

      說明: 此類別只是對Context類別的一層包裝,這個類別的構造函數包含了一個真正的context引用,即ContextIml
      
部分source code:

  1. public class ContextWrapper extends Context {  
  2.     Context mBase;  //這属性指向一個ContextIm實例,一般在創建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); 
  14.     }  
  15. }  

   ContextThemeWrapper

 Path:/frameworks/base/core/java/android/view/ContextThemeWrapper.java

      說明:此類別內部包含了Theme相關的接口,這邊的值由android:theme所指定。只有Activity需要Theme,Service不需要Theme所以Service直接繼承ContextWrapper類別。

      源代码(部分)如下:

  1. public class ContextThemeWrapper extends ContextWrapper {  
  2.      //這属性指向一個ContextIm實例,一般在創建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子類別, 更多imformation大家可以自行参考source code




什麼時候創建Context?

了解了Context繼承關係以後,接下來分析應用程式在什麼情況下需要創建Context對象? 應用程式創建Context實例的情況有以下幾種

      1、創建Application時, 而且整個App共一個Application對象

      2、創建Service對象時

      3、創建Activity對象時

 

      由此可知一個app所擁有的Context個數是:

 

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


     具體創建Context的時機

     1、創建Application對象的時機

       每個應用程式第一次啟動的時候,都會先建立一個Application。

       如果要跟應用程式啟動一個Activity流程比較的話,創建Application的時機在創建handleBindApplication()方法中,此函式在 ActivityThread.java類別中 ,如下:

  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(this, null, mActivityThread);  //初始化ContextIml的相關屬性  
  15.         ///新建一個Application對象   
  16.         app = mActivityThread.mInstrumentation.newApplication(  
  17.                 cl, appClass, appContext);  
  18.        appContext.setOuterContext(app);  //將Application實例傳給ContextImpl           
  19.     }   
  20.     ...  
  21. }  

    2、創建Activity對象的時機

       透過startActivity()或startActivityForResult()要求啟動一個Activity時,如果系统檢測需要新建一個Activity時,就會使用handleLaunchActivity(),這個方法在調用performLaunchActivity(),去創建一個Activity,並且回調onCreate(),onStart()方法等, 函式都位於 ActivityThread.java類別 ,如下:


  1. private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {  
  2.     ...  
  3.     Activity a = performLaunchActivity(r, customIntent);  //啟動一個Activity  
  4. }  
  5. private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {  
  6.     ...  
  7.     Activity activity = null;  
  8.     try {  
  9.         //創建一個Activity實例  
  10.         java.lang.ClassLoader cl = r.packageInfo.getClassLoader();  
  11.         activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);  
  12.     }  
  13.     if (activity != null) {  
  14.         ContextImpl appContext = new ContextImpl();      //創建一個Activity實例   
  15.         appContext.init(r.packageInfo, r.token, this);   //初始化ContextIml的相關屬性 
  16.         appContext.setOuterContext(activity);            //將Activity訊息傳遞给ContextImpl實例  
  17.         ...  
  18.     }  
  19.     ...      
  20. }  


  3、創建Service對象的時機

       透過startService或者bindService,如果系统檢測到需要新建一個Service實例,就會使用handleCreateService(),完成相關數據操作。handleCreateService()函數位於 ActivityThread.java,如下:

  1. private final void handleCreateService(CreateServiceData data){  
  2.     ...  
  3.     //創建一個Service實例  
  4.     Service service = null;  
  5.     try {  
  6.         java.lang.ClassLoader cl = packageInfo.getClassLoader();  
  7.         service = (Service) cl.loadClass(data.info.name).newInstance();  
  8.     } catch (Exception e) {  
  9.     }  
  10.     ...  
  11.     ContextImpl context = new ContextImpl(); //創建一個ContextImpl實例  
  12.     context.init(packageInfo, null, this);   //初始化
  13.     // 獲得之前創建的application的訊息
  14.     Application app = packageInfo.makeApplication(false, mInstrumentation);  
  15.     //把Service訊息傳遞给ContextImpl實例  
  16.     context.setOuterContext(service);  
  17.     ...  
  18. }  

    另外,需要強調的是,通過對ContextImp的分析可知,其方法的大多數操作都是直接調用其属性mPackageInfo(此屬性類行為PackageInfo)的相關方法而來。這说明了ContextImp是一層包裝,而PackageInfo才是真正操作的類別。而一個App裡的有ContextIml實例,都對應一個packageInfo對象。



0 0
原创粉丝点击