最近遇到一个bug,当应用加了多进程后,比如总共进程数为N,会出现在`startService()`时`onStartCommand()`方法会被重复调用`(N-1)`次的奇怪现象。

***
## 祸起
>最近遇到两个模块互不相干却受到影响的奇怪问题,一个push模块和一个DaemonProcess模块在一起后,会出现如下现像的问题
***
当DaemonProcess为应用加了多进程后,比如总共进程数为N,会出现push模块在`startService()`时`onStartCommand()`方法会被重复调用`(N-1)`次的奇怪现象。
***

## 寻踪

* 因为我们用的是Jpush的原因,一开始以为是Jpush,但最后发现是因为引用多进程的原因
* 再寻找下去发现 调用一次`startService()`时`onStartCommand()`运行多次
* 而这两者有何关系呢

## 举证

> Demo测试:
> 首先在Application中申明四个service,其中`ServiceA`和`ServiceC`都各自另开一个进程,`ServiceB`和`ServiceD`都在主进程中,AndroidManifest.xml如下:

```

<service android:name=".ServiceA"
android:process="com.hujiang.test.servicea"
android:exported="true"/>

<service android:name=".ServiceB"
android:exported="false"/>

<service android:name=".ServiceC"
android:process="com.hujiang.test.servicec"
android:exported="true"/>

<service android:name=".ServiceD"
android:exported="false"/>

```

此时在Application中启动四个Service
```

startService(new Intent(this, ServiceA.class));
startService(new Intent(this, ServiceB.class));
startService(new Intent(this, ServiceC.class));
startService(new Intent(this, ServiceD.class));

```
同时各Service打下如下log:

```
public static final String TAG = ServiceB.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG,"onCreate" + "pid:" + android.os.Process.myPid());
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG,"onStartCommand" + "pid:" + android.os.Process.myPid());
return super.onStartCommand(intent, flags, startId);
}

```

在log中会发现
`onCreate()`方法各执行一遍,这个是正常的,但`onStartCommand()`方法目前执行了三遍,因为共3个进程。

## 真相

1. N个进程,N个独立的虚拟机,Application被N次初使化
2. 处理时应该在Application中分进程初始化数据

<!--more-->
## 剑谱

如下解决方案

mProcessName = getCurrentProcessName(this);
Log.i(TAG, "onCreate" + "getProcessName:" + mProcessName);
Log.i(TAG, "init_all_process");
if(TextUtils.equals(mProcessName, getPackageName())){
Log.i(TAG, "init_main_process");
} else if(TextUtils.equals(getProcessName(this, android.os.Process.myPid()), "com.hujiang.test.servicea")){
Log.i(TAG, "init_a_process");
}else if(TextUtils.equals(getProcessName(this, android.os.Process.myPid()), "com.hujiang.test.servicec")){
Log.i(TAG, "init_c_process");
}

获取当前进程名称:

private String getCurrentProcessName(Context context) {
int pid = android.os.Process.myPid();
ActivityManager mActivityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager
.getRunningAppProcesses()) {
if (appProcess.pid == pid) {
return appProcess.processName;
}
}
return null;
}

分别在自己的进程中初始化

小议Android多进程以致Application多次初始化的更多相关文章

  1. 【转】Android多进程总结一:生成多进程(android:process属性)

    前言 正常情况下,一个apk启动后只会运行在一个进程中,其进程名为apk的包名,所有的组件都会在这个进程中运行,以下为DDMS的进程截屏: com.biyou.multiprocess为进程名,也是a ...

  2. 【转】 Android自定义捕获Application全局异常

    大家都知道,现在安装Android系统的手机版本和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出现崩溃的现象,开发者个人不可能购买所有设备逐个调试,所以在程序发布出去之后,如果出现了 ...

  3. Android 多进程编程 15问15答!

    ps:阅读本文 需要对android 多进程编程有一定了解. 1.Android中总共有几种方式进行IPC? 答:一共有两种,一种是binder 还有一种是socket.Binder 大家用的比较多. ...

  4. Android(java)学习笔记120:Android中的Application类用法

    1.简介 如果想在整个应用中使用全局变量,在java中一般是使用静态变量,public类型:而在android中如果使用这样的全局变量就不符合Android的框架架构,但是可以使用一种更优雅的方式就是 ...

  5. Android(java)学习笔记61:Android中的 Application类用法

    1. 简介 如果想在整个应用中使用全局变量,在java中一般是使用静态变量,public类型:而在android中如果使用这样的全局变量就不符合Android的框架架构,但是可以使用一种更优雅的方式就 ...

  6. 关于jni编译32位、64位动态库(Android.mk和Application.mk文件)

    最近新项目需要编译64位的动态库,这里记录如何配置. 在jni目录下加入Android.mk和Application.mk文件. Application.mk APP_ABI := armeabi a ...

  7. 利用Android多进程机制来分割组件

    android对于内存有一定的限制,很多手机上对内存的限制是完全不同的.我们的应用程序其实就是一个进程,这个进程是完全独立的,这个进程分配的内存是一定的,所以我们经常会遇到OOM的问题.但,你可能不知 ...

  8. 在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务(老罗学习笔记5)

    在数字科技日新月异的今天,软件和硬件的完美结合,造就了智能移动设备的流行.今天大家对iOS和Android系统的趋之若鹜,一定程度上是由于这两个系统上有着丰富多彩的各种应用软件.因此,软件和硬件的关系 ...

  9. 在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6578352 在数字科技日新月异的今天,软件和硬 ...

随机推荐

  1. Hangfire 在asp.net core环境的使用

    hf被定义为分布式后台服务,更加类似job作业的服务做作业的插件有quartz.net,JobScheduler 等当然,都有一些分别和适用的场景.1.安装需要安装Hangfire.CoreHangf ...

  2. 【洛谷P1159】排行榜

    排行榜 题目链接 看到题解中一个很巧妙的做法: 先确定SAME的位置, 将DOWN的按输入顺序从上往下输出 再将UP的接着从上往下输出 这样便可以保证DOWN的人名次一定下降了 UP的人名次一定上升了 ...

  3. java常见验证邮箱、电话号码、日期等格式

    package besttone.utils; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 90%的验证 ...

  4. 【题解】UVA11584 Partitioning by Palindromes

    UVA11584 https://www.luogu.org/problemnew/show/UVA11584 暑假开始刷lrj紫/蓝书DP题 这几天做的一道 思路 预处理出所有的回文串是否存在 前提 ...

  5. PAT1067. Sort with Swap(0, *) (25) 并查集

    PAT1067. Sort with Swap(0, *) (25) 并查集 题目大意 给定一个序列, 只能进行一种操作: 任一元素与 0 交换位置, 问最少需要多少次交换. 思路 最优解就是每次 0 ...

  6. 创建VS工程使用神经网络库——FANN

    编译: sourceforge上的FANN库带VS2010的工程,我机器上装的VS2005,用不了,愁人,只能手动创建工程了,编译不过,度娘不管用,FQ麻烦,用雅虎搜到一个工程的创建配置,调整配置试一 ...

  7. linux 怎么查看系统的环境变量 与设置jdk 系统环境变量

    1.win 7 ,win10 怎么查看,添加系统环境的变量,大家都非常清楚的.但是linux 的 却不一定哦. 打开终端输入 :  “echo $PATH “ or  “export ”      如 ...

  8. oracle中lock和latch的用途

    本文向各位阐述Oracle的Latch机制,Latch,用金山词霸翻译是门插栓,闭锁,专业术语叫锁存器,我开始接触时就不大明白为什么不写Lock,不都是锁吗?只是翻译不同而以?研究过后才知道两者有很大 ...

  9. iOS之网络请求及各类错误代码含义总结(包含AFN错误码大全)

    转自http://blog.csdn.net/wangyanchang21/article/details/50932191 在很多时候都会遇到错误, 还会带有一些 Error Code , 比如在各 ...

  10. 清除.svn文件

    清除以.svn结尾的文件: 新建一文本,然后复制以下代码进去,然后保存成clean.bat即可,它会把当前文件夹以及以下的所有匹配文件都给删除了 @echo on color 2f mode con: ...