• Android中Context具体解释 ---- 你所不知道的Context


                                                

                                                                                           本文原创 ,转载必须注明出处 :http://blog.csdn.net/qinjuning

                 前言:本文是我读《Android内核剖析》第7章 后形成的读书笔记 ,在此向欲了解Android框架的书籍推荐此书。

     

            大家好,  今天给大家介绍下我们在应用开发中最熟悉而陌生的朋友-----Context类 ,说它熟悉,是应为我们在开发中

       时刻的在与它打交道,比如:Service、BroadcastReceiver、Activity等都会利用到Context的相关方法 ; 说它陌生,全然是

       由于我们真正的不懂Context的原理、类结构关系。一个简单的问题是,一个应用程序App中存在多少个Context实例对象呢?

       一个、两个? 在此先卖个关子吧。读了本文,相信您会豁然开朗的 。

     

          Context,中文直译为“上下文”,SDK中对其说明例如以下:

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

      is 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、该类是一个抽象(abstract class)类,Android提供了该抽象类的详细实现类(后面我们会讲到是ContextIml类)。

            3、通过它我们能够获取应用程序的资源和类,也包含一些应用级别操作,比如:启动一个Activity,发送广播,接受Intent

          信息 等。。

     

     

       于是,我们能够利用该Context对象去构建应用级别操作(application-level operations) 。

     

     一、Context相关类的继承关系

                             

     

      相关类介绍:

     

       Context类    路径: /frameworks/base/core/java/android/content/Context.java

                说明:  抽象类,提供了一组通用的API。

          源码(部分)例如以下:   

    public abstract class Context {
    	 ...
     	 public abstract Object getSystemService(String name);  //获得系统级服务
    	 public abstract void startActivity(Intent intent);     //通过一个Intent启动Activity
    	 public abstract ComponentName startService(Intent service);  //启动Service
    	 //依据文件名称得到SharedPreferences对象
    	 public abstract SharedPreferences getSharedPreferences(String name,int mode);
    	 ...
    }

     

      ContextIml.java类  路径 :/frameworks/base/core/java/android/app/ContextImpl.java

              说明:该Context类的实现类为ContextIml,该类实现了Context类的功能。请注意,该函数的大部分功能都是直接调用

          其属性mPackageInfo去完毕,这点我们后面会讲到。    

             源码(部分)例如以下:

    /**
     * Common implementation of Context API, which provides the base
     * context object for Activity and other application components.
     */
    class ContextImpl extends Context{
    	//全部Application程序公用一个mPackageInfo对象
        /*package*/ ActivityThread.PackageInfo mPackageInfo;
        
        @Override
        public Object getSystemService(String name){
        	...
        	else if (ACTIVITY_SERVICE.equals(name)) {
                return getActivityManager();
            } 
        	else if (INPUT_METHOD_SERVICE.equals(name)) {
                return InputMethodManager.getInstance(this);
            }
        } 
        @Override
        public void startActivity(Intent intent) {
        	...
        	//開始启动一个Activity
            mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);
        }
    }


     

      ContextWrapper类 路径 :frameworksasecorejavaandroidcontentContextWrapper.java

            说明: 正如其名称一样,该类仅仅是对Context类的一种包装,该类的构造函数包括了一个真正的Context引用,即ContextIml

           对象。    源码(部分)例如以下:

    public class ContextWrapper extends Context {
        Context mBase;  //该属性指向一个ContextIml实例,一般在创建Application、Service、Activity时赋值
        
        //创建Application、Service、Activity,会调用该方法给mBase属性赋值
        protected void attachBaseContext(Context base) {
            if (mBase != null) {
                throw new IllegalStateException("Base context already set");
            }
            mBase = base;
        }
        @Override
        public void startActivity(Intent intent) {
            mBase.startActivity(intent);  //调用mBase实例方法
        }
    }


     

       ContextThemeWrapper类 路径:/frameworks/base/core/java/android/view/ContextThemeWrapper.java

          说明:该类内部包括了主题(Theme)相关的接口,即android:theme属性指定的。仅仅有Activity须要主题,Service不须要主题,

       所以Service直接继承于ContextWrapper类。

          源码(部分)例如以下:

    public class ContextThemeWrapper extends ContextWrapper {
    	 //该属性指向一个ContextIml实例,一般在创建Application、Service、Activity时赋值
    	 
    	 private Context mBase;
    	//mBase赋值方式相同有一下两种
    	 public ContextThemeWrapper(Context base, int themeres) {
    	        super(base);
    	        mBase = base;
    	        mThemeResource = themeres;
    	 }
    
    	 @Override
    	 protected void attachBaseContext(Context newBase) {
    	        super.attachBaseContext(newBase);
    	        mBase = newBase;
    	 }
    }
    

     

         Activity类 、Service类 、Application类本质上都是Context子类, 很多其它信息大家能够自行參考源码进行理解。

     

    二、 什么时候创建Context实例 

          熟悉了Context的继承关系后,我们接下来分析应用程序在什么情况须要创建Context对象的?应用程序创建Context实例的

     情况有例如以下几种情况:

          1、创建Application 对象时, 并且整个App共一个Application对象

          2、创建Service对象时

          3、创建Activity对象时

     

        因此应用程序App共同拥有的Context数目公式为:

     

                         总Context实例个数 = Service个数 + Activity个数 + 1(Application相应的Context实例)

     

      详细创建Context的时机

     

         1、创建Application对象的时机

     

           每一个应用程序在第一次启动时,都会首先创建Application对象。假设相应用程序启动一个Activity(startActivity)流程比較

    清楚的话,创建Application的时机在创建handleBindApplication()方法中,该函数位于 ActivityThread.java类中 ,例如以下:

    //创建Application时同一时候创建的ContextIml实例
    private final void handleBindApplication(AppBindData data){
        ...
    	///创建Application对象
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        ...
    }
    
    public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
    	...
    	try {
            java.lang.ClassLoader cl = getClassLoader();
            ContextImpl appContext = new ContextImpl();    //创建一个ContextImpl对象实例
            appContext.init(this, null, mActivityThread);  //初始化该ContextIml实例的相关属性
            ///新建一个Application对象 
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
           appContext.setOuterContext(app);  //将该Application实例传递给该ContextImpl实例         
        } 
    	...
    }

     

     

        2、创建Activity对象的时机

     

           通过startActivity()或startActivityForResult()请求启动一个Activity时,假设系统检測须要新建一个Activity对象时,就会

      回调handleLaunchActivity()方法,该方法继而调用performLaunchActivity()方法,去创建一个Activity实例,而且回调

     onCreate(),onStart()方法等, 函数都位于 ActivityThread.java类 ,例如以下:

    //创建一个Activity实例时同一时候创建ContextIml实例
    private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {
    	...
    	Activity a = performLaunchActivity(r, customIntent);  //启动一个Activity
    }
    private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {
    	...
    	Activity activity = null;
        try {
        	//创建一个Activity对象实例
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
        }
        if (activity != null) {
            ContextImpl appContext = new ContextImpl();      //创建一个Activity实例
            appContext.init(r.packageInfo, r.token, this);   //初始化该ContextIml实例的相关属性
            appContext.setOuterContext(activity);            //将该Activity信息传递给该ContextImpl实例
            ...
        }
        ...    
    }

     

     

       3、创建Service对象的时机

     

           通过startService或者bindService时,假设系统检測到须要新创建一个Service实例,就会回调handleCreateService()方法,

     完毕相关数据操作。handleCreateService()函数位于 ActivityThread.java类,例如以下:

    //创建一个Service实例时同一时候创建ContextIml实例
    private final void handleCreateService(CreateServiceData data){
    	...
    	//创建一个Service实例
    	Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
        }
    	...
    	ContextImpl context = new ContextImpl(); //创建一个ContextImpl对象实例
        context.init(packageInfo, null, this);   //初始化该ContextIml实例的相关属性
        //获得我们之前创建的Application对象信息
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        //将该Service信息传递给该ContextImpl实例
        context.setOuterContext(service);
        ...
    }
    


     

        另外,须要强调一点的是,通过对ContextImp的分析可知,其方法的大多数操作都是直接调用其属性mPackageInfo(该属性类

    型为PackageInfo)的相关方法而来。这说明ContextImp是一种轻量级类,而PackageInfo才是真正重量级的类。而一个App里的

    有ContextIml实例,都相应同一个packageInfo对象。

                

     

         最后给大家分析利用Context获取SharedPreferences类的用法,SharedPreferences类想必大家都使用过,其一般获取方

    法就是通过调用getSharedPreferences()方法去依据相关信息获取SharedPreferences对象。详细流程例如以下:

     

        1 、调用  getSharedPreferences()获取相应的的文件,该函数实现功能例如以下:

     

    //Context类静态数据集合,以键值对保存了全部读取该xml文件后所形成的数据集合
    private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs = 
    	   new HashMap<File, SharedPreferencesImpl>(); 
    
    @Override
    public SharedPreferences getSharedPreferences(String name, int mode){
    	 //其所相应的SharedPreferencesImpl对象 ,该对象已一个HashMap集合保存了我们对该文件序列化结果
    	 SharedPreferencesImpl sp;  
         File f = getSharedPrefsFile(name);  //该包下是否存在相应的文件,不存在就新建一个
         synchronized (sSharedPrefs) {       //是否已经读取过该文件,是就直接返回该SharedPreferences对象
             sp = sSharedPrefs.get(f);
             if (sp != null && !sp.hasFileChanged()) {
                 //Log.i(TAG, "Returning existing prefs " + name + ": " + sp);
                 return sp;
             }
         }
         //下面为序列化该xml文件,同一时候将数据写到map集合中     
         Map map = null;
         if (f.exists() && f.canRead()) {
             try {
                 str = new FileInputStream(f);
                 map = XmlUtils.readMapXml(str);
                 str.close();
             } 
             ...
         }
         
         synchronized (sSharedPrefs) {
             if (sp != null) {
                 //Log.i(TAG, "Updating existing prefs " + name + " " + sp + ": " + map);
                 sp.replace(map);   //更新数据集合
             } else {
                 sp = sSharedPrefs.get(f);
                 if (sp == null) {  
                	 //新建一个SharedPreferencesImpl对象,而且设置其相关属性
                     sp = new SharedPreferencesImpl(f, mode, map);  
                     sSharedPrefs.put(f, sp);
                 }
             }
             return sp;
         }
    }
    

       2、 SharedPreferences 只是是个接口,它定义了一些操作xml文件的方法,其真正实现类为SharedPreferencesImpl ,该类是

        ContextIml的内部类,该类例如以下:

     

    //soga,这样的形式我们在分析Context ContextIml时接触过 
    //SharedPreferences仅仅是一种接口,其真正实现类是SharedPreferencesImpl类
    private static final class SharedPreferencesImpl implements SharedPreferences{
    	 private Map mMap;  //保存了该文件序列化结果后的操作, 键值对形式
    	 
    	 //通过key值获取相应的value值
    	 public String getString(String key, String defValue) {
             synchronized (this) {
                 String v = (String)mMap.get(key);
                 return v != null ? v : defValue;
             }
         }
    	 ...
    	 //获得该SharedPreferencesImpl对象相应的Edito类,对数据进行操作
    	 public final class EditorImpl implements Editor {
    		 private final Map<String, Object> mModified = Maps.newHashMap(); //保存了对键值变化的集合
    	 }
    }
    



           基本上获取SharedPreferences 对象就是这么来的,关于Context里的很多其它方法请大家參照源码认真学习吧。

  • 相关阅读:
    牛客IOI周赛17-提高组 卷积 生成函数 多项式求逆 数列通项公式
    6.3 省选模拟赛 Decompose 动态dp 树链剖分 set
    AtCoder Grand Contest 044 A Pay to Win 贪心
    5.29 省选模拟赛 树的染色 dp 最优性优化
    luogu P6097 子集卷积 FST FWT
    CF724C Ray Tracing 扩展欧几里得 平面展开
    5.30 省选模拟赛 方格操作 扫描线 特殊性质
    5.29 省选模拟赛 波波老师 SAM 线段树 单调队列 并查集
    Spring main方法中怎么调用Dao层和Service层的方法
    Bug -- WebService报错(两个类具有相同的 XML 类型名称 "{http://webService.com/}getPriceResponse"。请使用 @XmlType.name 和 @XmlType.namespace 为类分配不同的名称。)
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/3856197.html
Copyright © 2020-2023  润新知