【Android话题-3.3应用进程】谈谈你对Application的理解

考察内容:

  • 了解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)提供应用上下文
  • 它的类继承关系及生命周期,生命周期的调用顺序
  • 它的初始化原理
发布了114 篇原创文章 · 获赞 27 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/menghaocheng/article/details/104459365
今日推荐