您的位置:首页 > 移动开发

多进程导致 Application 多次执行的问题研究

2017-07-13 16:55 471 查看
在项目中我们有时会用到多进程,需要在 AndroidManifest 里进行声明 :

<activity
android:name=".RemoteActivity"
android:process=":remote"/>


启动这个 Activity 后,你的应用就有了两个进程,这时就有问题了,Application 类的生命周期也调用了两次了:

07-13 10:03:40.069 22804 22804 D MyApplication: onCreate
07-13 10:03:40.885 22846 22846 D MyApplication: onCreate


至于为什么 Appilication 类的生命周期为什么会被调用两次,我们需要从底层进行分析,重点是看 Appilication 实例是在什么地方创建的,创建后生命周期是如何调用的;Activity 和 Application 都是普通的类,他们是在 ActivityThread 中创建的,并且给予了它们生命周期回调;

具体 Activity 启动流程可以看 Activity的启动流程

这里分析下与 Appilication 相关的内容

AMS 在收到发起者的 startActivity 请求后执行 ActivityStackSupervisor 的 startSpecificActivityLocked 方法

void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);

r.task.stack.setLaunchTime(r);

if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
}
}

mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}


这里调用了 AMS 的 getProcessRecordLocked 方法来查是否在 AMS 中有相关的记录(应用的每个进程名字都会记录在 AMS 中),如果没有,返回的 app 为 null, 这时 调用的是 startProcessLocked 方法

private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
...
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
...
}


在这里创建了一个新的进程,并且调用了 ActivityThread 的 main 方法,在 main 方法里创建了 ActivityThread 对象,也就是说每个进程对应了一个 ActivityThread 对象,然后 AMS 会通知 ActivityThread 的 handleLaunchActivity 来启动 Activity:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...

Activity a = performLaunchActivity(r, customIntent);

...
}


在这里调用 performLaunchActivity 创建了一个 Activity 和 Application

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
} catch (Exception e) {
...
}

try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);

...

if (activity != null) {
...

if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}

return activity;
}


在这里先创建了 Activity 实例,再创建 Appilication 实例,并调用了 Activity 的 onCreate 方法,其中,在 makeApplication 里调用了 Application 的 onCreate 方法:

public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
...
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
...
instrumentation.callApplicationOnCreate(app);

return app;
}


总结下,由于创建了新的进程,每个进程会创建自己的 ActivityThread 实例,每个 ActivityThread 又会创建自己的 Application 实例并且会调用它的 onCreate 方法;也就是说每个进程都会有自己的 Appilication 实例,而这个实例都用的同一个类来创建的,所以你在这个类里面写的东西当然会被执行多次;

所以这就是为什么同一个应用多进程会造成 Application 的生命周期方法会调用多次;

解决办法是在 Application 的生命周期方法里对进程名进行判断,如果不是同进程就不要执行一些不必要的东西了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android
相关文章推荐