考察内容:
- 了解Application的作用(初级)
- 熟悉Application的类继承关系以及生命周期(中级)
- 深入理解Application的初始化原理(高级)
Application有什么作用?
(首先它是一个系统组件,生命周期很长,只要应用在,它就在)
- 保存用户进程内的全局变量
- 初始化操作
- 提供应用上下文
Application的特点:
- 活得长(只有应用在,它就在)
- 生得早(Application的创建是排在四大组件前面的)
- Application是跟应用走的,不是跟进程走的,进程创建了几个应用就有几个Application
Application类的继承关系
- Application extends ContextWrapper
- ContextWrapper extends Context
class Application extends ContextWrapper implements XXX{
}
public class Context Wrapper extends Context{
Context mBase;
public ContextWrapper(Context base){
mBase = base;
}
protected void attachBaseContext(Context base){
mBase = base;
}
}
Applicatoin的生命周期
Application怎么初始化?
进程入口函数:
public static void main(String[] args){
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread;
//主要用于应用端向AMS打报告
thread.attach(false);
Looper.loop();
throw new RuntimeExceptiom("Main thread loop unexpectedly exited");
}
private void attach(){
//获取ActivityManager的的Binder对象
final IActivityManager mgr = ActivityManagerNative.getDefault();
try{
//
mgr.attachApplication(mAppThread);
}catch(RemoteException ex){
//Ignore
}
}
//跑在AMS端:
public final void attachApplication(IApplicationThread thread){
synchronized(this){
attachApplicationLocked(thread, callingPid);
}
}
//跑在AMS端:
boolean attachApplicationLocked(IApplicationThread thread, ...){
......
thread.bindApplication(...);
......
}
//应用端:(binder线程)
public final void bindApplication(...){
AppBindData data = new AppBindData();
......
sendMessage(H.BIND_APPLICATION, data);
}
//应用端在主线程处理bindApplication的函数:
private void handleBindApplication(AppBindData data){
//获取描述应用安装包的信息
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
//创建Application对象
Application app = data.info.makeApplication(...);
//调用app.onCreate
mInstrumentation.callApplicationOnCreate(app);
}
public Application makeApplication(...){
if(mApplication != null){
return mApplication;
}
ContextImpl appContext = ContextImpl.createAppContext(...);
app = mActivityThread.mInstrumentation.newApplication(...);
return app;
}
Application newApplicatoin(ClassLoader cl, String className, Context context){
//加载一个类
return newApplication(cl.loadClass(className), context);
}
Static Application newApplication(Class<?> clazz, Context context){
//然后调用这个类的构造函数对创建一个Application对象
Application app = (Application)clazz.newInstance();
//最后把context附给app
app.attach(context);
return app;
}
//虽然Application是一个Context但它只是一个空壳,真正干活的是一个名为mBase Context成员
final void attach(Context context){
attachBaseContext(context); //给mBase赋值
}
关键函数:
- new Application()
- application.attachBaseContext()
- application.onCreate()
注意问题:
1.不要在Application的生命周期回调中执行耗时操作
boolean attachApplicationLocked(IApplicationThread thread, ...){
..
thread.bindApplication(...);
...
//bindApplication后处理pending的组件:
mStackSupervisor.attachApplicationLocked(...);
mServices.attachApplicationLocked(app, processName);
sendPendingBroadcastLocked(app);
...
}
bindApplication后处理pending的组件,包括Activity、Service、Broadcast等,本来在启动这些组件的时候它的应用是没用启动的,现在应用进程启动好了,而且Application也初始化好了,就可以去处理这些待启动的组件了,这些组件的启动操作最终是要在应用进程执行的,比如Activity的生命周期是要在应用的UI线程中调用的。如果Application耗时太久,那么将会耽误应用的组件启动。
2.Application使用静态变量时产生的一个bug
Application中有一个静态变量name,MainActivity会去设置这个name,设置完之后马上跳转到TestActivity,Test读出name,正常情况是没什么问题的。但是如果这里把应用切到后台, 过了一段时间系统因为内存不足把应用杀掉了,再把应用切回来时,系统会重建这个应用,包括重建Application、恢复TestActivity,但这时候Application中的name是没有初始化的,TestActivity拿到的name就是null,这样就可能发生异常。
回归:谈谈你对Application的理解
- 它的作用是什么?
a)保存用户进程内的全局变量
b)初始化操作
c)提供应用上下文 - 它的类继承关系及生命周期,生命周期的调用顺序
- 它的初始化原理