Context 介绍

安卓真难学,搜达一堆博文,看得似懂非懂。
以下转自 http://www.cnblogs.com/jingmengxintang/p/7889311.html

https://www.cnblogs.com/tsingke/p/9127758.html
1、Context 概念

Context是个抽象类,通过类的结构可以看到:Activity、Service、Application都是Context的子类;

从Android系统的角度来理解:Context是一个场景,描述的是一个应用程序环境的信息,即上下文,代表与操作系统的交互的一种过程。

从程序的角度上来理解:Context是个抽象类,而Activity、Service、Application等都是该类的一个实现。

查看类的继承关系:ctrl + H (Windows系统)
在这里插入图片描述
应用在三种情况下会创建Context对象(即通常说的context):
1> 创建Application 对象时,即第一次启动app时。 整个App共一个Application对象,所以也只有一个Application 的Context,Application销毁,它也销毁;
2> 创建Activity对象时。Activity销毁,它也销毁;
3> 创建Service对象时。Service销毁,它也销毁。

由此可以得到应用程序App可以创建的Context(Activity和Service没启动就不会创建)个数公式一般为:
总Context实例个数 = Service个数 + Activity个数 + 1(Application对应的Context对象)

2.Context 继承结构
在这里插入图片描述
Context的继承结构还是稍微有点复杂的,可以看到,直接子类有两个,一个是ContextWrapper,一个是ContextImpl。那么从名字上就可以看出,ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现类。ContextWrapper又有三个直接的子类,ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一个带主题的封装类,而它有一个直接子类就是Activity。在这里我们看到了几个所比较熟悉的面孔,Activity、Service、还有Application。由此,我们可以大致得出结论,Context一共有三种类型,分别是Application、Activity和Service。这三个类虽然分别各种承担着不同的作用,但它们都属于Context的一种,而它们具体Context的功能则是由ContextImpl类去实现的。其实Context还有一个直接子类MockContext,,该类可以理解为模拟context,源码位于android.test.mock包中,API文档中找不到。当我们要测试一个模块A,他依赖于其它模块B,但是模块B还没实现或现在根本没有,这时就要使用MockContext和其他同样位于android.test.mock包中的类。通过它可以注入其他依赖,模拟Context,或者监听测试的类。主要是在TDD中使用这些MOCK类来代替真实的类,用法可参考Mock在Android TDD中的使用。想查看ContextImpl的源码时,无法找到ContextImpl这个类。由于ContextImpl是抽象类Context的实现类。然而查看Context类的继承结构,如下图:没有发现ContextImpl。后来查到原因是:这个文件是保护文件,就是注解了是内部保护文件,所以在eclipse,Androidstudio中都是不显示的。所以可以去SDk的安装目录中的sources文件夹中直接找那个Java文件,/android-sdk/sources/android-19/android/app/ContextImpl.java。Mockcontext同理。

3、Context 常用方法
// 获取应用程序包的AssetManager实例
public abstract AssetManager getAssets();

// 获取应用程序包的Resources实例
public abstract Resources getResources();

// 获取PackageManager实例,以查看全局package信息
public abstract PackageManager getPackageManager();

// 获取应用程序包的ContentResolver实例
public abstract ContentResolver getContentResolver();

// 它返回当前进程的主线程的Looper,此线程分发调用给应用组件(activities, services等)
public abstract Looper getMainLooper();

// 返回当前进程的单实例全局Application对象的Context
public abstract Context getApplicationContext();

// 从string表中获取本地化的、格式化的字符序列
public final CharSequence getText(int resId) {
return getResources().getText(resId);
}

// 从string表中获取本地化的字符串
public final String getString(int resId) {
return getResources().getString(resId);
}

public final String getString(int resId, Object… formatArgs) {
return getResources().getString(resId, formatArgs);
}

// 返回一个可用于获取包中类信息的class loader
public abstract ClassLoader getClassLoader();

// 返回应用程序包名
public abstract String getPackageName();

// 返回应用程序信息
public abstract ApplicationInfo getApplicationInfo();

// 根据文件名获取SharedPreferences
public abstract SharedPreferences getSharedPreferences(String name,
int mode);

// 其根目录为: Environment.getExternalStorageDirectory()
public abstract File getExternalFilesDir(String type);

// 返回应用程序obb文件路径
public abstract File getObbDir();

// 启动一个新的activity
public abstract void startActivity(Intent intent);

// 启动一个新的activity
public void startActivityAsUser(Intent intent, UserHandle user) {
throw new RuntimeException(“Not implemented. Must override in a subclass.”);
}

// 启动一个新的activity
// intent: 将被启动的activity的描述信息
// options: 描述activity将如何被启动
public abstract void startActivity(Intent intent, Bundle options);

// 启动多个新的activity
public abstract void startActivities(Intent[] intents);

// 启动多个新的activity
public abstract void startActivities(Intent[] intents, Bundle options);

// 广播一个intent给所有感兴趣的接收者,异步机制
public abstract void sendBroadcast(Intent intent);

// 广播一个intent给所有感兴趣的接收者,异步机制
public abstract void sendBroadcast(Intent intent,String receiverPermission);
//发送有序广播
public abstract void sendOrderedBroadcast(Intent intent,String receiverPermission);

public abstract void sendOrderedBroadcast(Intent intent,
String receiverPermission, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
Bundle initialExtras);

public abstract void sendBroadcastAsUser(Intent intent, UserHandle user);

public abstract void sendBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission);

// 注册一个BroadcastReceiver,且它将在主activity线程中运行
public abstract Intent registerReceiver(BroadcastReceiver receiver,
IntentFilter filter);
//取消注册BroadcastReceiver
public abstract Intent registerReceiver(BroadcastReceiver receiver,
IntentFilter filter, String broadcastPermission, Handler scheduler);

public abstract void unregisterReceiver(BroadcastReceiver receiver);

// 请求启动一个application service
public abstract ComponentName startService(Intent service);

// 请求停止一个application service
public abstract boolean stopService(Intent service);

// 连接一个应用服务,它定义了application和service间的依赖关系
public abstract boolean bindService(Intent service, ServiceConnection conn,
int flags);

// 断开一个应用服务,当服务重新开始时,将不再接收到调用,
// 且服务允许随时停止
public abstract void unbindService(ServiceConnection conn);

// 返回系统级service
public abstract Object getSystemService(String name);
//检查权限
public abstract int checkPermission(String permission, int pid, int uid);

// 返回一个新的与application name对应的Context对象
public abstract Context createPackageContext(String packageName,
int flags) throws PackageManager.NameNotFoundException;

// 返回基于当前Context对象的新对象,其资源与display相匹配
public abstract Context createDisplayContext(Display display);

Context的主要功能为:
1)启动Activity
2)启动和停止Service
3)发送广播消息(Intent)
4)注册广播消息(Intent)接收者
5)可以访问APK中各种资源(如Resources和AssetManager等)
6)可以访问Package的相关信息
7)APK的各种权限管理

4、Context 如何获取

通常我们想要获取Context对象,主要有以下四种方法
1:View.getContext,返回当前View对象的Context对象,通常是当前正在展示的Activity对象。
2:Activity.getApplicationContext,获取当前Activity所在的(应用)进程的Context对象,通常我们使用Context对象时,要优先考虑这个全局的进程Context。
3:ContextWrapper.getBaseContext():用来获取一个ContextWrapper进行装饰之前的Context,可以使用这个方法,这个方法在实际开发中使用并不多,也不建议使用。
4:Activity.this 返回当前的Activity实例,如果是UI控件需要使用Activity作为Context对象,但是默认的Toast实际上使用ApplicationContext也可以。

public class MyActivity extends Activity {
Context mContext;
public void method() {

    mContext = this; //获取当前Activity的上下文,如果需要绑定Activity的生命周期,使用它

    mContext=MyActivity.this;//获取当前MyActivity的上下文,不方便使用this的时候推荐使用这种方式

    //调用Activity.getApplicationContext()
    mContext = getApplicationContext();//获取当前Application的上下文,如果需要绑定应用的生命周期,使用它

    //Activity.getApplication()
    mContext = getApplication();//获取当前Application的上下文,

    //调用ContextWrapper.getBaseContext()
    mContext = getBaseContext();//从上下文A内上下文访问上下文A,不建议使用,如果需要,推荐使用XxxClass.this直接指出上下文
}

}

public class MyView extends View {
Context mContext;
public void method() {

    //调用View.getContext()
    mContext = getContext(); //获取这个View运行所在地的上下文
}

}
1)this和getBaseContext()

this:代表当前,在Activity当中就是代表当前的Activity,换句话说就是Activity.this在Activity当中可以缩写为this。Activity.this的context 返回当前activity的上下文,属于activity ,activity 摧毁他就摧毁。
getBaseContext() 返回由构造函数指定或setBaseContext()设置的上下文。
复制代码
Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?>arg0, View arg1, int arg2, long arg3){
//Toast.makeText(getBaseContext(),“SELECTED”, Toast.LENGTH_SHORT).show();//可以使用它,但是不建议
Toast.makeText(MainActivity.this,“SELECTED”, Toast.LENGTH_SHORT).show();//推荐使用XxxClass.this直接指出了使用的是谁的上下文,更简捷。
//Toast.makeText(this,“SELECTED”, Toast.LENGTH_SHORT).show();//不可用,这里this指的不是Activity,而是spinner这个类。

}

}
复制代码

2)getApplicationContext()和getApplication()

getApplicationContext 取得的是当前app所使用的application,这在AndroidManifest中唯一指定。意味着,在当前app的任意位置使用这个函数得到的是同一个Context,getApplicationContext(): 返回应用的上下文,生命周期是整个应用,应用摧毁,它才摧毁。
getApplication():andorid 开发中共享全局数据;
getApplication()只能在Activity和Service里使用,指向的是Application对象,因为Application也是Context的一个子类,所以getApplication()可以被用来指向Context。

比如如果想要获取在应用清单文件中声明的类,最好不要使用getApplicationContext(),并且最好使用强制转换为自己自定义的Application,因为那样可能会得不到Application对象。

Log.i(“dyl”, "getApplication is = " + myApp);
Log.i(“dyl”, "getApplicationContext is = " + appContext);
通过上面的代码,打印得出两者的内存地址都是相同的,看来它们是同一个对象。其实这个结果也很好理解,因为前面已经说过了,Application本身就是一个Context,所以这里获取getApplicationContext()得到的结果就是Application本身的实例。那么问题来了,既然这两个方法得到的结果都是相同的,那么Android为什么要提供两个功能重复的方法呢?实际上这两个方法在作用域上有比较大的区别。getApplication()方法的语义性非常强,一看就知道是用来获取Application实例的,但是这个方法只有在Activity和Service中才能调用的到。那么也许在绝大多数情况下我们都是在Activity或者Service中使用Application的,但是如果在一些其它的场景,比如BroadcastReceiver中也想获得Application的实例,这时就可以借助getApplicationContext()方法了。

5.Context 应用场景

因为Context的具体能力是由ContextImpl类去实现的,所以在绝大多数场景下,Activity、Service和Application这三种类型的Context都是可以通用的。不过有几种场景比较特殊,比如启动Activity,还有弹出Dialog。出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。

Context的应用场景图

在这里插入图片描述

大家注意看到有一些NO上添加了一些数字,其实这些从能力上来说是YES,但是为什么说是NO呢?下面一个一个解释:

数字1:启动Activity在这些类中是可以的,但是需要创建一个新的task。一般情况不推荐。

数字2:在这些类中去layout inflate是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用。

数字3:在receiver为null时允许,在4.2或以上的版本中,用于获取黏性广播的当前值。(可以无视)

注:ContentProvider、BroadcastReceiver之所以在上述表格中,是因为在其内部方法中都有一个context用于使用。

好了,这里我们看下表格,重点看Activity和Application,可以看到,和UI相关的方法基本都不建议或者不可使用Application,并且,前三个操作基本不可能在Application中出现。实际上,只要把握住一点,凡是跟UI相关的,都应该使用Activity做为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以,当然了,注意Context引用的持有,防止内存泄漏。

6、Context 使用过程中的注意项

1)Activity mActivity =new Activity()

这样写语法上没有任何错误,Android的应用程序开发采用JAVA语言,Activity本质上也是一个对象。但是,

Android程序不像Java程序一样,随便创建一个类,写个main()方法就能运行,Android应用模型是基于组件的应用设计模式,组件的运行要有一个完整的Android工程环境,在这个环境下,Activity、Service等系统组件才能够正常工作,而这些组件并不能采用普通的Java对象创建方式,new一下就能创建实例了,而是要有它们各自的上下文环境,才能使得其正常工作。即走正常的onCreate-onStart-onResume。。。
2)大家在编写一些类时,例如工具类,可能会编写成单例的方式,这些工具类大多需要去访问资源,也就说需要Context的参与。

在这样的情况下,就需要注意Context的引用问题。

复制代码
public class CustomManager
{
private static CustomManager sInstance;
private Context mContext;

private CustomManager(Context context)  
{  
    this.mContext = context;  
}  

public static synchronized CustomManager getInstance(Context context)  
{  
    if (sInstance == null)  
    {  
        sInstance = new CustomManager(context);  
    }  
    return sInstance;  
}  

}
复制代码
对于上述的单例,大家应该都不陌生(请别计较getInstance的效率问题),内部保持了一个Context的引用;这么写是没有问题的,问题在于,这个Context哪来的我们不能确定,很大的可能性,你在某个Activity里面为了方便,直接传了个this;这样问题就来了,我们的这个类中的sInstance是一个static且强引用的,在其内部引用了一个Activity作为Context,也就是说,我们的这个Activity只要我们的项目活着,就没有办法进行内存回收。而我们的Activity的生命周期肯定没这么长,所以造成了内存泄漏。那么,我们如何才能避免这样的问题呢?有人会说,我们可以软引用,嗯,软引用,假如被回收了,你不怕NullPointException么。把上述代码做下修改:

复制代码
public static synchronized CustomManager getInstance(Context context)
{
if (sInstance == null)
{
sInstance = new CustomManager(context.getApplicationContext());
}
return sInstance;
}
复制代码
这样,我们就解决了内存泄漏的问题,因为我们引用的是一个ApplicationContext,它的生命周期和我们的单例对象一致。

3)Intent也要求指出上下文,如果想启动一个新的Activity,就必须在Intent中使用Activity的上下文,这样新启动的Activity才能和当前Activity有关联(在activity栈);也可以使用application的context,但是需要在Intent中添加 Intent.FLAG_ACTIVITY_NEW_TASK标志,当作一个新任务。ApplicationContext去启动一个LaunchMode为standard的Activity的时候会报错,非Activity类型的Context并没有所谓的任务栈,所以待启动的Activity就找不到栈了。解决这个问题的方法就是为待启动的Activity指定FLAG_ACTIVITY_NEW_TASK标记位,这样启动的时候就为它创建一个新的任务栈,而此时Activity是以singleTask模式启动的。所以这种用Application启动Activity的方式不推荐使用,Service同Application。

public static void openActivity(Context context){
Intent intent = new Intent(context.getApplicationContext(), SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.getApplicationContext().startActivity(intent);
}

参考博文:

http://blog.csdn.net/guolin_blog/article/details/47028975

http://www.jianshu.com/p/94e0f9ab3f1d

http://blog.csdn.net/u012585964/article/details/52268235

以下转自:
https://www.cnblogs.com/tsingke/p/9127758.html

Android中Context的作用以及Context的详细用法
本文我们一起来探讨一下关于Android中Context的作用以及Context的详细用法,这对我们学习Android的资源访问有很大的帮助,文章中也贴出了一些关于Android Context使用的示例代码,非常不错,以下是原文:

Context基本概念
Context是什么?

  1. Context是一个抽象类,其通用实现在ContextImpl类中。

  2. Context:是一个访问application环境全局信息的接口,通过它可以访问application的资源和相关的类,其主要功能如下:

启动Activity
启动和停止Service
发送广播消息(Intent)
注册广播消息(Intent)接收者
可以访问APK中各种资源(如Resources和AssetManager等)
可以访问Package的相关信息
APK的各种权限管理

从以上分析可以看出,Context就是一个对APK包无所不知的大管家,大家需要什么,直接问它就可以了。

Context与View的关系
View与Context(或Activity)的关系类似于明星与经纪人的关系,所以创建View时,必须明确指定其Context(即经纪人或大管家),否则View就成不了明星。

Context家族关系

Context关键函数
复制代码
1 public abstract class Context {
2
3 // 获取应用程序包的AssetManager实例
4 public abstract AssetManager getAssets();
5
6 // 获取应用程序包的Resources实例
7 public abstract Resources getResources();
8
9 // 获取PackageManager实例,以查看全局package信息
10 public abstract PackageManager getPackageManager();
11
12 // 获取应用程序包的ContentResolver实例
13 public abstract ContentResolver getContentResolver();
14
15 // 它返回当前进程的主线程的Looper,此线程分发调用给应用组件(activities, services等)
16 public abstract Looper getMainLooper();
17
18 // 返回当前进程的单实例全局Application对象的Context
19 public abstract Context getApplicationContext();
20
21 // 从string表中获取本地化的、格式化的字符序列
22 public final CharSequence getText(int resId) {
23 return getResources().getText(resId);
24 }
25
26 // 从string表中获取本地化的字符串
27 public final String getString(int resId) {
28 return getResources().getString(resId);
29 }
30
31 public final String getString(int resId, Object… formatArgs) {
32 return getResources().getString(resId, formatArgs);
33 }
34
35 // 返回一个可用于获取包中类信息的class loader
36 public abstract ClassLoader getClassLoader();
37
38 // 返回应用程序包名
39 public abstract String getPackageName();
40
41 // 返回应用程序信息
42 public abstract ApplicationInfo getApplicationInfo();
43
44 // 根据文件名获取SharedPreferences
45 public abstract SharedPreferences getSharedPreferences(String name,
46 int mode);
47
48 // 其根目录为: Environment.getExternalStorageDirectory()
49 /*
50 * @param type The type of files directory to return. May be null for
51 * the root of the files directory or one of
52 * the following Environment constants for a subdirectory:
53 * {@link android.os.Environment#DIRECTORY_MUSIC},
54 * {@link android.os.Environment#DIRECTORY_PODCASTS},
55 * {@link android.os.Environment#DIRECTORY_RINGTONES},
56 * {@link android.os.Environment#DIRECTORY_ALARMS},
57 * {@link android.os.Environment#DIRECTORY_NOTIFICATIONS},
58 * {@link android.os.Environment#DIRECTORY_PICTURES}, or
59 * {@link android.os.Environment#DIRECTORY_MOVIES}.
60 /
61 public abstract File getExternalFilesDir(String type);
62
63 // 返回应用程序obb文件路径
64 public abstract File getObbDir();
65
66 // 启动一个新的activity
67 public abstract void startActivity(Intent intent);
68
69 // 启动一个新的activity
70 public void startActivityAsUser(Intent intent, UserHandle user) {
71 throw new RuntimeException(“Not implemented. Must override in a subclass.”);
72 }
73
74 // 启动一个新的activity
75 // intent: 将被启动的activity的描述信息
76 // options: 描述activity将如何被启动
77 public abstract void startActivity(Intent intent, Bundle options);
78
79 // 启动多个新的activity
80 public abstract void startActivities(Intent[] intents);
81
82 // 启动多个新的activity
83 public abstract void startActivities(Intent[] intents, Bundle options);
84
85 // 广播一个intent给所有感兴趣的接收者,异步机制
86 public abstract void sendBroadcast(Intent intent);
87
88 // 广播一个intent给所有感兴趣的接收者,异步机制
89 public abstract void sendBroadcast(Intent intent,String receiverPermission);
90
91 public abstract void sendOrderedBroadcast(Intent intent,String receiverPermission);
92
93 public abstract void sendOrderedBroadcast(Intent intent,
94 String receiverPermission, BroadcastReceiver resultReceiver,
95 Handler scheduler, int initialCode, String initialData,
96 Bundle initialExtras);
97
98 public abstract void sendBroadcastAsUser(Intent intent, UserHandle user);
99
100 public abstract void sendBroadcastAsUser(Intent intent, UserHandle user,
101 String receiverPermission);
102
103 // 注册一个BroadcastReceiver,且它将在主activity线程中运行
104 public abstract Intent registerReceiver(BroadcastReceiver receiver,
105 IntentFilter filter);
106
107 public abstract Intent registerReceiver(BroadcastReceiver receiver,
108 IntentFilter filter, String broadcastPermission, Handler scheduler);
109
110 public abstract void unregisterReceiver(BroadcastReceiver receiver);
111
112 // 请求启动一个application service
113 public abstract ComponentName startService(Intent service);
114
115 // 请求停止一个application service
116 public abstract boolean stopService(Intent service);
117
118 // 连接一个应用服务,它定义了application和service间的依赖关系
119 public abstract boolean bindService(Intent service, ServiceConnection conn,
120 int flags);
121
122 // 断开一个应用服务,当服务重新开始时,将不再接收到调用,
123 // 且服务允许随时停止
124 public abstract void unbindService(ServiceConnection conn);
125
126 // 返回系统级service句柄
127 /

128 * @see #WINDOW_SERVICE
129 * @see android.view.WindowManager
130 * @see #LAYOUT_INFLATER_SERVICE
131 * @see android.view.LayoutInflater
132 * @see #ACTIVITY_SERVICE
133 * @see android.app.ActivityManager
134 * @see #POWER_SERVICE
135 * @see android.os.PowerManager
136 * @see #ALARM_SERVICE
137 * @see android.app.AlarmManager
138 * @see #NOTIFICATION_SERVICE
139 * @see android.app.NotificationManager
140 * @see #KEYGUARD_SERVICE
141 * @see android.app.KeyguardManager
142 * @see #LOCATION_SERVICE
143 * @see android.location.LocationManager
144 * @see #SEARCH_SERVICE
145 * @see android.app.SearchManager
146 * @see #SENSOR_SERVICE
147 * @see android.hardware.SensorManager
148 * @see #STORAGE_SERVICE
149 * @see android.os.storage.StorageManager
150 * @see #VIBRATOR_SERVICE
151 * @see android.os.Vibrator
152 * @see #CONNECTIVITY_SERVICE
153 * @see android.net.ConnectivityManager
154 * @see #WIFI_SERVICE
155 * @see android.net.wifi.WifiManager
156 * @see #AUDIO_SERVICE
157 * @see android.media.AudioManager
158 * @see #MEDIA_ROUTER_SERVICE
159 * @see android.media.MediaRouter
160 * @see #TELEPHONY_SERVICE
161 * @see android.telephony.TelephonyManager
162 * @see #INPUT_METHOD_SERVICE
163 * @see android.view.inputmethod.InputMethodManager
164 * @see #UI_MODE_SERVICE
165 * @see android.app.UiModeManager
166 * @see #DOWNLOAD_SERVICE
167 * @see android.app.DownloadManager
168 */
169 public abstract Object getSystemService(String name);
170
171 public abstract int checkPermission(String permission, int pid, int uid);
172
173 // 返回一个新的与application name对应的Context对象
174 public abstract Context createPackageContext(String packageName,
175 int flags) throws PackageManager.NameNotFoundException;
176
177 // 返回基于当前Context对象的新对象,其资源与display相匹配
178 public abstract Context createDisplayContext(Display display);
179 }
复制代码

ContextImpl关键成员和函数
复制代码
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 private final static String TAG = “ContextImpl”;
7 private final static boolean DEBUG = false;
8
9 private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
10 new HashMap<String, SharedPreferencesImpl>();
11
12 /package/ LoadedApk mPackageInfo; // 关键数据成员
13 private String mBasePackageName;
14 private Resources mResources;
15 /package/ ActivityThread mMainThread; // 主线程
16
17 @Override
18 public AssetManager getAssets() {
19 return getResources().getAssets();
20 }
21
22 @Override
23 public Looper getMainLooper() {
24 return mMainThread.getLooper();
25 }
26
27 @Override
28 public Object getSystemService(String name) {
29 ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
30 return fetcher == null ? null : fetcher.getService(this);
31 }
32
33 @Override
34 public void startActivity(Intent intent, Bundle options) {
35 warnIfCallingFromSystemProcess();
36 if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
37 throw new AndroidRuntimeException(
38 “Calling startActivity() from outside of an Activity "
39 + " context requires the FLAG_ACTIVITY_NEW_TASK flag.”
40 + " Is this really what you want?");
41 }
42 mMainThread.getInstrumentation().execStartActivity(
43 getOuterContext(), mMainThread.getApplicationThread(), null,
44 (Activity)null, intent, -1, options);
45 }
46 }
复制代码

ContextWrapper
它只是对Context类的一种封装,它的构造函数包含了一个真正的Context引用,即ContextImpl对象。

复制代码
1 /**
2 * Proxying implementation of Context that simply delegates all of its calls to
3 * another Context. Can be subclassed to modify behavior without changing
4 * the original Context.
5 /
6 public class ContextWrapper extends Context {
7 Context mBase; //该属性指向一个ContextIml实例
8
9 public ContextWrapper(Context base) {
10 mBase = base;
11 }
12
13 /
*
14 * Set the base context for this ContextWrapper. All calls will then be
15 * delegated to the base context. Throws
16 * IllegalStateException if a base context has already been set.
17 *
18 * @param base The new base context for this wrapper.
19 * 创建Application、Service、Activity,会调用该方法给mBase属性赋值
20 */
21 protected void attachBaseContext(Context base) {
22 if (mBase != null) {
23 throw new IllegalStateException(“Base context already set”);
24 }
25 mBase = base;
26 }
27
28 @Override
29 public Looper getMainLooper() {
30 return mBase.getMainLooper();
31 }
32
33 @Override
34 public Object getSystemService(String name) {
35 return mBase.getSystemService(name);
36 }
37
38 @Override
39 public void startActivity(Intent intent) {
40 mBase.startActivity(intent);
41 }
42 }
复制代码

ContextThemeWrapper
该类内部包含了主题(Theme)相关的接口,即android:theme属性指定的。只有Activity需要主题,Service不需要主题,所以Service直接继承于ContextWrapper类。

复制代码
1 /**
2 * A ContextWrapper that allows you to modify the theme from what is in the
3 * wrapped context.
4 */
5 public class ContextThemeWrapper extends ContextWrapper {
6 private Context mBase;
7 private int mThemeResource;
8 private Resources.Theme mTheme;
9 private LayoutInflater mInflater;
10 private Configuration mOverrideConfiguration;
11 private Resources mResources;
12
13 public ContextThemeWrapper() {
14 super(null);
15 }
16
17 public ContextThemeWrapper(Context base, int themeres) {
18 super(base);
19 mBase = base;
20 mThemeResource = themeres;
21 }
22
23 @Override protected void attachBaseContext(Context newBase) {
24 super.attachBaseContext(newBase);
25 mBase = newBase;
26 }
27
28 @Override public void setTheme(int resid) {
29 mThemeResource = resid;
30 initializeTheme();
31 }
32
33 @Override public Resources.Theme getTheme() {
34 if (mTheme != null) {
35 return mTheme;
36 }
37
38 mThemeResource = Resources.selectDefaultTheme(mThemeResource,
39 getApplicationInfo().targetSdkVersion);
40 initializeTheme();
41
42 return mTheme;
43 }
44 }
复制代码

何时创建Context
应用程序在以下几种情况下创建Context实例:

  1. 创建Application 对象时, 而且整个App共一个Application对象

  2. 创建Service对象时

  3. 创建Activity对象时

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

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

ActivityThread消息处理函数与本节相关的内容如下:

复制代码
1 public void handleMessage(Message msg) {
2 if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
3 switch (msg.what) {
4 case LAUNCH_ACTIVITY: { // 创建Activity对象
5 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “activityStart”);
6 ActivityClientRecord r = (ActivityClientRecord)msg.obj;
7
8 r.packageInfo = getPackageInfoNoCheck(
9 r.activityInfo.applicationInfo, r.compatInfo);
10 handleLaunchActivity(r, null);
11 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
12 } break;
13
14 case BIND_APPLICATION: // 创建Application对象
15 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “bindApplication”);
16 AppBindData data = (AppBindData)msg.obj;
17 handleBindApplication(data);
18 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
19 break;
20
21 case CREATE_SERVICE: // 创建Service对象
22 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “serviceCreate”);
23 handleCreateService((CreateServiceData)msg.obj);
24 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
25 break;
26
27 case BIND_SERVICE: // Bind Service对象
28 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “serviceBind”);
29 handleBindService((BindServiceData)msg.obj);
30 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
31 break;
32 }
33 }
复制代码

创建Application对象时创建Context实例
每个应用程序在第一次启动时,都会首先创建一个Application对象。从startActivity流程可知,创建Application的时机在handleBindApplication()方法中,该函数位于 ActivityThread.java类中 ,相关代码如下:

复制代码
1 // ActivityThread.java
2 private void handleBindApplication(AppBindData data) {
3 try {
4 // If the app is being launched for full backup or restore, bring it up in
5 // a restricted environment with the base application class.
6 Application app = data.info.makeApplication(data.restrictedBackupMode, null);
7 mInitialApplication = app;
8 …
9 } finally {
10 StrictMode.setThreadPolicy(savedPolicy);
11 }
12 }
13
14 // LoadedApk.java
15 public Application makeApplication(boolean forceDefaultAppClass,
16 Instrumentation instrumentation) {
17 if (mApplication != null) {
18 return mApplication;
19 }
20
21 Application app = null;
22
23 String appClass = mApplicationInfo.className;
24 if (forceDefaultAppClass || (appClass == null)) {
25 appClass = “android.app.Application”;
26 }
27
28 try {
29 java.lang.ClassLoader cl = getClassLoader();
30 ContextImpl appContext = new ContextImpl(); // 创建ContextImpl实例
31 appContext.init(this, null, mActivityThread);
32 app = mActivityThread.mInstrumentation.newApplication(
33 cl, appClass, appContext);
34 appContext.setOuterContext(app); // 将Application实例传递给Context实例
35 } catch (Exception e) {
36 …
37 }
38 mActivityThread.mAllApplications.add(app);
39 mApplication = app;
40
41 return app;
42 }
43 private Context createBaseContextForActivity(ActivityClientRecord r,
44 final Activity activity) {
45 ContextImpl appContext = new ContextImpl(); // 创建ContextImpl实例
46 appContext.init(r.packageInfo, r.token, this);
47 appContext.setOuterContext(activity);
48
49 // For debugging purposes, if the activity’s package name contains the value of
50 // the “debug.use-second-display” system property as a substring, then show
51 // its content on a secondary display if there is one.
52 Context baseContext = appContext;
53 String pkgName = SystemProperties.get(“debug.second-display.pkg”);
54 if (pkgName != null && !pkgName.isEmpty()
55 && r.packageInfo.mPackageName.contains(pkgName)) {
56 DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
57 for (int displayId : dm.getDisplayIds()) {
58 if (displayId != Display.DEFAULT_DISPLAY) {
59 Display display = dm.getRealDisplay(displayId);
60 baseContext = appContext.createDisplayContext(display);
61 break;
62 }
63 }
64 }
65 return baseContext;
66 }
复制代码

创建Service对象时创建Context实例
通过startService或者bindService时,如果系统检测到需要新创建一个Service实例,就会回调handleCreateService()方法,完成相关数据操作。handleCreateService()函数位于 ActivityThread.java类,如下:

复制代码
1 private void handleCreateService(CreateServiceData data) {
2 // If we are getting ready to gc after going to the background, well
3 // we are back active so skip it.
4 unscheduleGcIdler();
5
6 LoadedApk packageInfo = getPackageInfoNoCheck(
7 data.info.applicationInfo, data.compatInfo);
8 Service service = null;
9 try {
10 java.lang.ClassLoader cl = packageInfo.getClassLoader();
11 service = (Service) cl.loadClass(data.info.name).newInstance();
12 } catch (Exception e) {
13 if (!mInstrumentation.onException(service, e)) {
14 throw new RuntimeException(
15 "Unable to instantiate service " + data.info.name
16 + ": " + e.toString(), e);
17 }
18 }
19
20 try {
21 if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
22
23 ContextImpl context = new ContextImpl(); // 创建ContextImpl实例
24 context.init(packageInfo, null, this);
25
26 Application app = packageInfo.makeApplication(false, mInstrumentation);
27 context.setOuterContext(service);
28 service.attach(context, this, data.info.name, data.token, app,
29 ActivityManagerNative.getDefault());
30 service.onCreate();
31 mServices.put(data.token, service);
32 try {
33 ActivityManagerNative.getDefault().serviceDoneExecuting(
34 data.token, 0, 0, 0);
35 } catch (RemoteException e) {
36 // nothing to do.
37 }
38 } catch (Exception e) {
39 if (!mInstrumentation.onException(service, e)) {
40 throw new RuntimeException(
41 "Unable to create service " + data.info.name
42 + ": " + e.toString(), e);
43 }
44 }
45 }
复制代码
复制代码
1 private void handleCreateService(CreateServiceData data) {
2 // If we are getting ready to gc after going to the background, well
3 // we are back active so skip it.
4 unscheduleGcIdler();
5
6 LoadedApk packageInfo = getPackageInfoNoCheck(
7 data.info.applicationInfo, data.compatInfo);
8 Service service = null;
9 try {
10 java.lang.ClassLoader cl = packageInfo.getClassLoader();
11 service = (Service) cl.loadClass(data.info.name).newInstance();
12 } catch (Exception e) {
13 if (!mInstrumentation.onException(service, e)) {
14 throw new RuntimeException(
15 "Unable to instantiate service " + data.info.name
16 + ": " + e.toString(), e);
17 }
18 }
19
20 try {
21 if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
22
23 ContextImpl context = new ContextImpl(); // 创建ContextImpl实例
24 context.init(packageInfo, null, this);
25
26 Application app = packageInfo.makeApplication(false, mInstrumentation);
27 context.setOuterContext(service);
28 service.attach(context, this, data.info.name, data.token, app,
29 ActivityManagerNative.getDefault());
30 service.onCreate();
31 mServices.put(data.token, service);
32 try {
33 ActivityManagerNative.getDefault().serviceDoneExecuting(
34 data.token, 0, 0, 0);
35 } catch (RemoteException e) {
36 // nothing to do.
37 }
38 } catch (Exception e) {
39 if (!mInstrumentation.onException(service, e)) {
40 throw new RuntimeException(
41 "Unable to create service " + data.info.name
42 + ": " + e.toString(), e);
43 }
44 }
45 }
复制代码

小结
通过对ContextImp的分析可知,其方法的大多数操作都是直接调用其属性mPackageInfo(该属性类型为PackageInfo)的相关方法而来。这说明ContextImp是一种轻量级类,而PackageInfo才是真正重量级的类。而一个App里的所有ContextImpl实例,都对应同一个packageInfo对象。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值