首页 > 其他分享 >2014.4.25.12.51_context_2014.4.25_Android种的Context详解

2014.4.25.12.51_context_2014.4.25_Android种的Context详解

时间:2023-06-02 20:07:14浏览次数:38  
标签:25 ... 创建 Application 实例 Context Activity 2014.4


Android中Context详解 ---- 你所不知道的Context
一、Context相关类的继承关系 2
二、 什么时候创建Context实例 5
从上可知一下三点,即:
1、它描述的是一个应用程序环境的信息,即上下文。
2、该类是一个抽象(abstract class)类,Android提供了该抽象类的具体实现类(后面我们会讲到是ContextIml类)。
3、通过它我们可以获取应用程序的资源和类,也包括一些应用级别操作,例如:启动一个Activity,发送广播,接受Intent信息 等。。
于是,我们可以利用该Context对象去构建应用级别操作(application-level operations) 。
一、Context相关类的继承关系
相关类介绍:
Context类 路径: /frameworks/base/core/java/android/content/Context.java
说明: 抽象类,提供了一组通用的API。源代码(部分)如下:

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去完成,这点我们后面会讲到。
源代码(部分)如下:

10	/** 
11	 * Common implementation of Context API, which provides the base 
12	 * context object for Activity and other application components. 
13	 */  
14	class ContextImpl extends Context{  
15	    //所有Application程序公用一个mPackageInfo对象  
16	    /*package*/ ActivityThread.PackageInfo mPackageInfo;  
17	      
18	    @Override  
19	    public Object getSystemService(String name){  
20	        ...  
21	        else if (ACTIVITY_SERVICE.equals(name)) {  
22	            return getActivityManager();  
23	        }   
24	        else if (INPUT_METHOD_SERVICE.equals(name)) {  
25	            return InputMethodManager.getInstance(this);  
26	        }  
27	    }   
28	    @Override  
29	    public void startActivity(Intent intent) {  
30	        ...  
31	        //开始启动一个Activity  
32	        mMainThread.getInstrumentation().execStartActivity(  
33	            getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);  
34	    }  
35	}

ContextWrapper类 路径:\frameworks\base\core\java\android\content\ContextWrapper.java
说明: 正如其名称一样,该类只是对Context类的一种包装,该类的构造函数包含了一个真正的Context引用,即ContextIml对象。
源代码(部分)如下:

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

ContextThemeWrapper类 路径:/frameworks/base/core/java/android/view/ContextThemeWrapper.java
说明:该类内部包含了主题(Theme)相关的接口,即android:theme属性指定的。只有Activity需要主题,Service不需要主题, 所以Service直接继承于ContextWrapper类。
源代码(部分)如下:

51	public class ContextThemeWrapper extends ContextWrapper {  
52	     //该属性指向一个ContextIml实例,一般在创建Application、Service、Activity时赋值  
53	       
54	     private Context mBase;  
55	    //mBase赋值方式同样有一下两种  
56	     public ContextThemeWrapper(Context base, int themeres) {  
57	            super(base);  
58	            mBase = base;  
59	            mThemeResource = themeres;  
60	     }  
61	  
62	     @Override  
63	     protected void attachBaseContext(Context newBase) {  
64	            super.attachBaseContext(newBase);  
65	            mBase = newBase;  
66	     }  
67	}
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类中 ,如下:

68	//创建Application时同时创建的ContextIml实例  
69	private final void handleBindApplication(AppBindData data){  
70	    ...  
71	    ///创建Application对象  
72	    Application app = ata.info.makeApplication(data.restrictedBackupMode, null);  
73	    ...  
74	}  
75	public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {  
76	    ...  
77	    try {  
78	        java.lang.ClassLoader cl = getClassLoader();  
79	        ContextImpl appContext = new ContextImpl();    //创建一个ContextImpl对象实例  
80	        appContext.init(this, null, mActivityThread);  //初始化该ContextIml实例的相关属性  
81	        ///新建一个Application对象   
82	        app = mActivityThread.mInstrumentation.newApplication(  
83	                cl, appClass, appContext);  
84	       appContext.setOuterContext(app);  //将该Application实例传递给该ContextImpl实例           
85	    }   
86	    ...  
87	}
2、创建Activity对象的时机
   通过startActivity()或startActivityForResult()请求启动一个Activity时,如果系统检测需要新建一个Activity对象时,就会

回调handleLaunchActivity()方法,该方法继而调用performLaunchActivity()方法,去创建一个Activity实例,并且回调
onCreate(),onStart()方法等, 函数都位于 ActivityThread.java类 ,如下:

88	//创建一个Activity实例时同时创建ContextIml实例  
89	private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {  
90	    ...  
91	    Activity a = performLaunchActivity(r, customIntent);  //启动一个Activity  
92	}  
93	private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {  
94	    ...  
95	    Activity activity = null;  
96	    try {  
97	        //创建一个Activity对象实例  
98	        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();  
99	        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);  
100	    }  
101	    if (activity != null) {  
102	        ContextImpl appContext = new ContextImpl();      //创建一个Activity实例  
103	        appContext.init(r.packageInfo, r.token, this);   //初始化该ContextIml实例的相关属性  
104	        appContext.setOuterContext(activity);            //将该Activity信息传递给该ContextImpl实例  
105	        ...  
106	    }  
107	    ...      
108	}  



 3、创建Service对象的时机
       通过startService或者bindService时,如果系统检测到需要新创建一个Service实例,就会回调handleCreateService()方法,
 完成相关数据操作。handleCreateService()函数位于 ActivityThread.java类,如下:
109	//创建一个Service实例时同时创建ContextIml实例  
110	private final void handleCreateService(CreateServiceData data){  
111	    ...  
112	    //创建一个Service实例  
113	    Service service = null;  
114	    try {  
115	        java.lang.ClassLoader cl = packageInfo.getClassLoader();  
116	        service = (Service) cl.loadClass(data.info.name).newInstance();  
117	    } catch (Exception e) {  
118	    }  
119	    ...  
120	    ContextImpl context = new ContextImpl(); //创建一个ContextImpl对象实例  
121	    context.init(packageInfo, null, this);   //初始化该ContextIml实例的相关属性  
122	    //获得我们之前创建的Application对象信息  
123	    Application app = packageInfo.makeApplication(false, mInstrumentation);  
124	    //将该Service信息传递给该ContextImpl实例  
125	    context.setOuterContext(service);  
126	    ...  
127	}
另外,需要强调一点的是,通过对ContextImp的分析可知,其方法的大多数操作都是直接调用其属性mPackageInfo(该属性类

型为PackageInfo)的相关方法而来。这说明ContextImp是一种轻量级类,而PackageInfo才是真正重量级的类。而一个App里的
所有ContextIml实例,都对应同一个packageInfo对象。
最后给大家分析利用Context获取SharedPreferences类的使用方法,SharedPreferences类想必大家都使用过,其一般获取方
法就是通过调用getSharedPreferences()方法去根据相关信息获取SharedPreferences对象。具体流程如下:
1 、调用 getSharedPreferences()获取对应的的文件,该函数实现功128//Context类静态数据集合,以键值对保存了所有读取该xml文件后所形成的数据集合

129private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs =
 130 new HashMap<File, SharedPreferencesImpl>();
 131
 132@Override
 133public SharedPreferences getSharedPreferences(String name, int mode){
 134 //其所对应的SharedPreferencesImpl对象 ,该对象已一个HashMap集合保存了我们对该文件序列化结果
 135 SharedPreferencesImpl sp;
 136 File f = getSharedPrefsFile(name); //该包下是否存在对应的文件,不存在就新建一个
 137 synchronized (sSharedPrefs) { //是否已经读取过该文件,是就直接返回该SharedPreferences对象
 138 sp = sSharedPrefs.get(f);
 139 if (sp != null && !sp.hasFileChanged()) {
 140 //Log.i(TAG, "Returning existing prefs " + name + ": " + sp);
 141 return sp;
 142 }
 143 }
 144 //以下为序列化该xml文件,同时将数据写到map集合中
 145 Map map = null;
 146 if (f.exists() && f.canRead()) {
 147 try {
 148 str = new FileInputStream(f);
 149 map = XmlUtils.readMapXml(str);
 150 str.close();
 151 }
 152 …
 153 }
 154
 155 synchronized (sSharedPrefs) {
 156 if (sp != null) {
 157 //Log.i(TAG, "Updating existing prefs " + name + " " + sp + ": " + map);
 158 sp.replace(map); //更新数据集合
 159 } else {
 160 sp = sSharedPrefs.get(f);
 161 if (sp == null) {
 162 //新建一个SharedPreferencesImpl对象,并且设置其相关属性
 163 sp = new SharedPreferencesImpl(f, mode, map);
 164 sSharedPrefs.put(f, sp);
 165 }
 166 }
 167 return sp;
 168 }
 169} 2、

SharedPreferences 不过是个接口,它定义了一些操作xml文件的方法,其真正实现类为SharedPreferencesImpl ,该类是
ContextIml的内部类,该类如下:

170	//soga,这种形式我们在分析Context ContextIml时接触过   
171	//SharedPreferences只是一种接口,其真正实现类是SharedPreferencesImpl类  
172	private static final class SharedPreferencesImpl implements SharedPreferences{  
173	     private Map mMap;  //保存了该文件序列化结果后的操作, 键值对形式  
174	       
175	     //通过key值获取对应的value值  
176	     public String getString(String key, String defValue) {  
177	         synchronized (this) {  
178	             String v = (String)mMap.get(key);  
179	             return v != null ? v : defValue;  
180	         }  
181	     }  
182	     ...  
183	     //获得该SharedPreferencesImpl对象对应的Edito类,对数据进行操作  
184	     public final class EditorImpl implements Editor {  
185	         private final Map<String, Object> mModified = Maps.newHashMap(); //保存了对键值变化的集合  
186	     }  
187	}  
188	//soga,这种形式我们在分析Context ContextIml时接触过 
189	//SharedPreferences只是一种接口,其真正实现类是SharedPreferencesImpl类
190	private static final class SharedPreferencesImpl implements SharedPreferences{
191	     private Map mMap;  //保存了该文件序列化结果后的操作, 键值对形式
192	     
193	     //通过key值获取对应的value值
194	     public String getString(String key, String defValue) {
195	         synchronized (this) {
196	             String v = (String)mMap.get(key);
197	             return v != null ? v : defValue;
198	         }
199	     }
200	     ...
201	     //获得该SharedPreferencesImpl对象对应的Edito类,对数据进行操作
202	     public final class EditorImpl implements Editor {
203	         private final Map<String, Object> mModified = Maps.newHashMap(); //保存了对键值变化的集合
204	     }
205	}
206

本文转自网络,具体出处不详。


标签:25,...,创建,Application,实例,Context,Activity,2014.4
From: https://blog.51cto.com/u_11797608/6404716

相关文章

  • 2014.4.19.12.27_switch_8.28_java switch语句使用注意的四大细节_0.01
    javaswitch语句使用注意的四大细节很多朋友在使用javaswitch语句时,可能没有注意到一些细节,本文将详细介绍使用javaswitch语句四大要点,需要的朋友可以参考下。switch语句的格式如下:(它的功能是选出一段代码执行)switch(整数选择因子){case整数值1:语句;break;case整数值......
  • Leetcode 2559. 统计范围内的元音字符串数
    题目:给你一个下标从0开始的字符串数组words以及一个二维整数数组queries。每个查询queries[i]=[l,r]会要求我们统计在words中下标在l到r范围内(包含这两个值)并且以元音开头和结尾的字符串的数目。返回一个整数数组,其中数组的第i个元素对应第i个查询的答案......
  • 杜教筛 & Min25 筛
    发现这个东西很容易忘,果然还是理解不够吧,写一篇博客方便以后复习。杜教筛目的是要求\(S(n)=\sum_{i=1}^nf(i)\)。我们需要构造两个函数\(g,h\)满足\(f*g=h\),其中\(h\)是一个积性函数且能快速求和。考虑求\(\sum_{i=1}^n\sum_{d|i}f(d)g(\dfrac{i}{d})=\sum_{i=1}......
  • 25宫格
    .icon-list{display:grid;grid-template-columns:repeat(5,1fr);/*划分为5列*/grid-template-rows:repeat(5,1fr);/*划分为5行*/gap:12px;/*间隔为12像素*/.icon-item{width:48px;height:48px;border-radius......
  • CAN 总线 MCP2551T-I/SN 收发器代替型号 DP2551-I/ST完全pin对pin兼容
    目前世界上使用最广泛的CAN收发器当属NXP(原飞利浦半导体)的各种收发器了。MCP2551是一个可容错的高速CAN器件,可作为CAN协议控制器和物理总线接口。MCP2551可为CAN协议控制器提供差分收发能力,它完全符合ISO-11898标准,包括能满足24V电压要求。它的工作速率高达1Mb/s......
  • 2517. 礼盒的最大甜蜜度
    题目链接:2517.礼盒的最大甜蜜度方法:二分解题思路题目意思:当前有\(n\)类糖果,从\(0\)到\(n-1\)编号,\(price[i]\)表示第\(i\)类糖果的价格,现要你在其中选择\(k\)类不同的糖果,组成一个集合\(s\),该集合的值为集合中两种糖果差的绝对值的最小值,现在要求你计算所有可......
  • 如何在tree中添加一个 contextmenu 事件!
    关键点就是TreeList上下文中要有这个被包装了的handleContextMenu定义TreeList时,继承了一些东西,还可以重写一些东西。 本例中,TreeList上下文捕获到右键菜单事件后,将该事件传递给了自定义的函数itemcontextmenu1对应的函数应该returnfalse来阻止默认菜单的行为。在函......
  • 如何在tree中添加一个 contextmenu 事件?
     /***添加绑定事件*<pre><code>*//绑定单个事件*list.on('itemclick',function(ev){*alert('21');*});*//绑定多个事件*list.on('itemrendereditemupdated',function(......
  • 2517. 礼盒的最大甜蜜度
    给你一个正整数数组price,其中price[i]表示第i类糖果的价格,另给你一个正整数k。商店组合k类不同糖果打包成礼盒出售。礼盒的甜蜜度是礼盒中任意两种糖果价格绝对差的最小值。返回礼盒的最大甜蜜度。来源:力扣(LeetCode)链接:https://leetcode.cn/problems/maxim......
  • CI854K01 3BSE025961R1保护电机/变压器/馈线/发电机等免受接地故障影响
    CI854K013BSE025961R1保护电机/变压器/馈线/发电机等免受接地故障影响CI854K013BSE025961R1CI854K013BSE025961R1 EFR用于保护控制面板和配电盘免受接地故障影响,保护电机/变压器/馈线/发电机等免受接地故障影响,可以保护炼油厂/纸浆工业/配电等危险和敏感行业。PFR:PFR(Ph......