小議Android多進程以致Application多次初始化


最近遇到一個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;
}


分別在自己的進程中初始化


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM