亲自实践:.多进程Application onCreate多次执行

时间:2021-11-17 04:02:20

最近在使用小米、友盟等推送的时候遇到这样的问题,就是突然发现Application的onCreate执行了两遍,所以,针对这一问题,我也进行了一些测试和资料查阅,对于问题原因基本不是那么模糊了,首先我们来看下为何Application的onCreate会执行两次:

这样的代码想必并不陌生:

 android:process=":remote"

    这里就不对多进程做太多解释,':'开头则为私有进程,只能与本应用交互,若无':',则为全局进程,在一些权限配置之后即可实现不同应用与它的交互。

      我是这样配置的:

<service
android:name=".MyService"
android:process=":remote"
android:enabled="true"
>

</service>
 
Application中执行
startService(new Intent(this, MyService.class));
MainActivity中
MyApplication.fff.fff = 333;final Timer timer = new Timer();timer.schedule(new TimerTask() {    @Override    public void run() {        Log.i("Jiaqi", "activity ###### application -> " + getApplicationContext());        Log.i("Jiaqi", "activity ###### numberObj -> " + MyApplication.fff);        Log.i("Jiaqi", "activity ###### timer -> " + timer + "->" + MyApplication.fff.fff);    }}, 3000, 3000);
MyService中
@Overridepublic void onCreate() {    super.onCreate();    Log.i("Jiaqi", "MyService onCreate");    MyApplication.fff.fff = 555;    final Timer timer = new Timer();    timer.schedule(new TimerTask() {        @Override        public void run() {            Log.i("Jiaqi", "service ###### application -> " + getApplicationContext());            Log.i("Jiaqi", "service ###### numberObj -> " + MyApplication.fff);            Log.i("Jiaqi", "service ###### timer -> " + timer + "->" + (MyApplication.fff.fff++));        }    }, 3000, 3000);}
@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {    Log.i("Jiaqi","onStartCommand" + "pid:" + android.os.Process.myPid() + ", a = " + (a++));    return super.onStartCommand(intent, flags, startId);}

 

问题就出在这里,在Android中,如果有新进程创建,由于进程本身需要一个Application,所以当走到startService时,发现MyService是新进程,所以会新建一个进程放MyService,但MyService又需要一个Application,所以Application会再次执行一遍。 Application onCreate两次的原因知道了,那随后的问题又来了,资源是如何分配的呢?

会不会重复加载资源?重复执行方法呢?答案是:会的!以下就是我测试时打印出的log(分两次打印):

第一次:

I/Jiaqi   ( 2711): Application #####  application -> com.example.huai.mipushdemo.MyApplication@39145b5c

I/Jiaqi   ( 2711): Application #####  fff -> com.example.huai.mipushdemo.Number@6a91e65

I/Jiaqi   ( 2744): Application #####  application -> com.example.huai.mipushdemo.MyApplication@39145b5c

I/Jiaqi   ( 2744): Application #####  fff -> com.example.huai.mipushdemo.Number@6a91e65

I/Jiaqi   ( 2744): MyService onCreate

I/Jiaqi   ( 2744): onStartCommandpid:2744, a = 0

I/Jiaqi   ( 2744): onStartCommandpid:2744, a = 1

I/Jiaqi   ( 2744): service ###### application -> com.example.huai.mipushdemo.MyApplication@39145b5c

I/Jiaqi   ( 2744): service ###### numberObj -> com.example.huai.mipushdemo.Number@6a91e65

I/Jiaqi   ( 2744): service ###### timer -> java.util.Timer@a123be1->555

I/Jiaqi   ( 2711): activity ###### application -> com.example.huai.mipushdemo.MyApplication@39145b5c

I/Jiaqi   ( 2711): activity ###### numberObj -> com.example.huai.mipushdemo.Number@6a91e65

I/Jiaqi   ( 2711): activity ###### timer -> java.util.Timer@ed1ea9f->333

I/Jiaqi   ( 2744): service ###### application -> com.example.huai.mipushdemo.MyApplication@39145b5c

I/Jiaqi   ( 2744): service ###### numberObj -> com.example.huai.mipushdemo.Number@6a91e65

I/Jiaqi   ( 2744): service ###### timer -> java.util.Timer@a123be1->556

I/Jiaqi   ( 2711): activity ###### application -> com.example.huai.mipushdemo.MyApplication@39145b5c

I/Jiaqi   ( 2711): activity ###### numberObj -> com.example.huai.mipushdemo.Number@6a91e65

I/Jiaqi   ( 2711): activity ###### timer -> java.util.Timer@ed1ea9f->333

第二次:

I/Jiaqi   ( 2051): application -> com.example.huai.mipushdemo.MyApplication@2639d148I

/Jiaqi   ( 2051): numberObj -> com.example.huai.mipushdemo.Number@a123be1I

/Jiaqi   ( 2051): timer -> java.util.Timer@9083d06->556I

/Jiaqi   ( 1964): application -> com.example.huai.mipushdemo.MyApplication@a123be1I

/Jiaqi   ( 1964): numberObj -> com.example.huai.mipushdemo.Number@ed1ea9fI

/Jiaqi   ( 1964): timer -> java.util.Timer@1ad787ec->333

从以上的log分析,第一次打印时,乍一看,我以为没有重新创建资源,因为引用都是一样的,但仔细一看,Application中的fff对象虽然引用一样,但是MainActivity(主进程)与MyService进程对其操作时,都是各变各的,所以并不是同一块内存区,所以,由于2个进程会有2个虚拟机运行,MyService进程很可能会复制主进程中的一切,之后再根据自己的操作去操作这块内存,与主进程就没关系了。这时再看第二次的测试,会发现,果然引用不一样,所以“复制”也不是每一次都会发生的。

接下来一个问题是  MyService onCreate一次,onStartCommond两次,这是为何?由于MyService单处一个进程,其进程名就是之前设置的 remote,所以并不会再次创建;onStartCommond调用了两次,因为每次startService都会进入这个回调,这也充分证明了startService被调用了两次!

所以根据以上分析,做个总结,那就是开发中如遇到多进程(n),那么在Application中初始化的资源会初始化(n)次,每个进程中都有一份这些对象,不会互相影响。

对于这一问题,我认为当遇到多进程的情况时,初始化需要区分进程:

private boolean shouldInit() {
ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE));
List<ActivityManager.RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
String mainProcessName = getPackageName();
int myPid = android.os.Process.myPid();

for (ActivityManager.RunningAppProcessInfo info : processInfos) {
Log.i("Jiaqi", "my.pid -> " + myPid + ",mainProcessName -> " + mainProcessName);
Log.i("Jiaqi", "info.pid -> " + info.pid + ",info.processName -> " + info.processName);

if (info.pid == myPid && mainProcessName.equals(info.processName)) {
return true;
}
}
return false;
}

以上返回true的地方即为主进程。


本人也是初识多进程,如若有问题,请指教!感谢~