考察内容:
- 了解Context的作用
- 熟悉Context的初始化流程
- 深入理解不同应用组件之间Context的区别
回答几个问题:
- 应用里面有多少个Context?不同的Context之间有什么区别?
- Activity里面的this和getBaseContext有什么区别?
- getApplication和getApplicationContext有什么区别?
- 应用组件的构造,onCreate、attachBaseContext调用顺序?
Context是一个抽象类
public abstract calss Context{
public abstract Resources getResources();
public abstract Object getSystemService(String name);
public abstract void startActivty(Intent intent);
public abstract void sendBroadcast(Intent intent);
......
}
其实现都在ContextImpl中
class ContextImpl extends Context{
final ActivityThread mMainThread; //核心类
final LoadedApk mPackageInfo; //安装包信息
private final ResourcesManager mResourcesManager; //系统资源相关
private final Resources mResources;
private Resoures.Theme mThreme = null; //主题相关
private PackageManager mPackageManager; //包管理
//系统服务缓存
final Object] mServiceCache = SystemServiceRegistry.createServiceCache();
}
正是因为有了Context这些应用组件才有意义,它们才能访问系统服务、访问系统资源,如果没有Context那么Activty不过是一个普通的java对象。
Context是在哪里创建的?
哪些组件有自己的Context?
- Application
- Activity
- Service
(Broadcast、ContentProvider是没有自己的Context的)
Application Context
【Application Context的初始化】:
Application Context是跟随Application一起初始化的,而Application又是跟随应用进程的启动一起初始化的。应用进程的启动是怎样的呢?先是zygote创建应用进程,应用进程启动后会执行一个java类的入口函数,也就是ActivityThread的main函数。这个函数会向AMS报告 :我已经启动好了。AMS收到之后就会下一道命令:创建Application。
AMS让应用创建Application,应用端的处理函数如下:
private void handleBindApplication(AppBindData data){
//先创建一个Application对象
Application app = data.info.makeApplication(...);
//然后调用它的onCreate回调
app.onCreate();
}
public Application makeApplication(...){
//先创建一个Context:实现就是newContextImpl(...)
ContextImpl appContext = ContextImpl.createAppContext(...);
Application app;
//然后再创建Application对象,传入appContext参数
app = mActivityThread.mInstrumentation.newApplication(appContext);
return app;
}
//创建Application对象:
application newApplication(ClassLoader cl, String className, Context context){
//先用classLoader对加载Application类
return newApplication(cl.loadClass(className), context);
}
Application newApplication(Class<?> clazz, Context context){
//然后再调用newInstance
//newInstance就会去调用类的构造函数,从而得到Application对象
Application app = (Application)clazz.newInstance();
//最后结app附上context
app.attach(context); //将调用attachBaseContext(context);
return app;
}
【Application的继承关系】:
public class Application extends ContextWrapper{
......
}
public class ContextWrapper extends Context{
Context mBase;
protected void attachBaseContext(Context base){
mBase = base;
}
public Context getBaseContext(){
return mBase;
}
@Overrid
public Resources getResources() {
return mBase.getResources();
}
@Override
public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
}
Application本身就是一个Context,怎么里面还包了一个Context呢?这是为什么呢?我们可以看到关于Context的所有调用其实都转手丢给了里边的mBase对象,这是一个典型的静态代理模式。如果我们用反射换掉了里面的mBase对象会怎样呢?比如调用getSystemService函数,结果有可能会跳转到另一个Context的实现里面,它就可以对返回的SystemService管理对象做一些手脚。这个机制一般在插件里会用到。
【Application的结论】:
- 继承关系:Application<-ContextWrapper<-context
- 调用顺序:->attachBaseContext->onCreate
- ContextWraper里面包含一个Context,调用都委托给它了
Activity Context
【Activty Context的初始化】:
Activity的Context是跟随Activity的启动的时候一起初始化的:
private Activity performLaunchActivity(){
Activity activity = null;
//创建Actvity对象
activity mInstrumentation.newActivity();
//获取之前创建好的application
Application app = r.packageInfo.makeApplication();
//为Activity创建一个Context:实现就是new ContextImpl()
Context appContext = createBaseContextForActivity(r, activity);
//把appContext和application附给activity
activity.attach(appContext, app, ...); //将调用attachBaseContext(context);
//调用Activity的生命周期函数
activity.onCreate();
return activity;
}
public Activity newActivity(ClassLoader cl, String className){
//先用ClassLoader加载Activity类,然后用newInstance就会去调用Acivity的构造函数,从而得到Activity的对象
return (Activity)cl.loadClass(className).newInstance();
}
【Activty的类继承关系】:
public class Activity extends ContextThemeWrapper{
...
}
public class ContextThemeWrapper extends ContextWrapper{
private int mThemeResource;
private Resources.Theme mTheme;
private LayoutInflater mInflater;
private Configuration mOverrideConfiguration;
private Resources mResources;
}
public class ContextWrapper extends Context{
Context mBase;
......
}
【Activity的结论】:
- Activity<-ContextThemeWrapper<-ContextWrapper
- 调用顺序,->attachBaseContext->onCreate
Service Context
【Service Context的初始化】:
private void handleCreateService(CreateServiceData data) {
Servie service = null;
//通过classLoader加载Service的类,然后调用newInstance
//newInstance将调用Service的构造函数从而获得一个Service对象
servie = (Service)cl.loadClass(data.info.name).newInstance();
//创建一个Context:实现就是new ContextImpl(...)
ContextImpl context = ContextImpl.createAppContext(this, packageInfo)
context.setOuterContext(service);
//获取之前创建的application对象
Application app = packageInfo.makeApplication();
//把context和application附给service
service.attach(context, app); //将调用attachBaseContext(context);
//调用Service生命周期
servcie.onCreate();
}
【Service的继承关系】:
public abstract class Service extends ContextWrapper{
......
}
BroadcastReceiver
public abstract class BroadcastReceiver {
public abstract void onReceive(Context context, Intent intent);
......
}
【广播结论】:
广播是一个抽象类,它没有继承Context抽象类,也没有关于Context的全局变量,只有一个onReceive抽象函数,而且这个函数带了一个参数:Context。如果是动态注册的广播,那么这个Context就是用context.registeReceiver注册广播时所用的context;如果是静态注册 的广播,它也不是Activty Context,而是以Application为mBase的ContextWrapper。
ContentProvider
public abstract class ContentProvider {
private Context mContext = null;
......
}
ContentProvider跟广播一样,也没有继承什么ContextWrapper,不过它里面有一个mContext成员变量,它是ContextProvider初始化的时候外面传进来的,传的是Application Context。随便提一下:ContentProvider的初始化虽然是在Application的构造函数以及attachBaseContext之后,但是它是在application.onCreate()之前调用的。也就是说ContentProvider它的onCreate是比application.onCreate要早。
回答几个问题:
- 应用里面有多少个Context?不同的Context之间有什么区别?
a)Activty的数个+Service的个数+Application的个数。应用可能是多进程的,因此Application可能有多个。区别:Activty因为要显示UI,因此它继承了ContextThemeWrapper,而Service和Application这种非UI组件则直接继承ContextWrapper。 - Activity里的this和getBaseContext有什么区别?
答:因为Activty是继承了Context,所以this就是返回Activity对象自己;而getBaseContext返回的是ContextWrapper里面的mBase。 - getApplication和getApplicationContext有什么区别?
答:getApplicationContext()是context里的一个抽象函数,而getApplication()是Activty和Service里特有的——它在别的地方不能用,比如在广播的onReciever(context)中的context是不能调getApplication()的,只能调getApplicationContext()。 - 应用组件的构造,onCreate、attachBaseContext调用顺序?
答:组件构造函数->attachBaseContext->onCreate
回归:谈谈你对Context的解理
- 说清楚Context的作用
a)Context是应用的上下文,有了Context应用组件就方便去访问系统资源、调用系统服务 - 说出应用中有几种Context,各自继承关系
- 说一下Context的初始化流程