坑的背景
在下是一個小小的Android研發,前幾天有個需求,需要接入Admob廣告。我們的App有多個進程。主進程和其中一個子進程都有涉及到廣告的邏輯。
?
坑是怎樣形成的
在接入Admob,成功獲取到廣告之后,開始調試展示、落地頁,等打點是否正常的時候。發現,展示沒問題,但是在子進程獲取的廣告,點擊是無法觸發打開落地頁的。
?
在之前的接入中已經知道了Admob廣告在點擊之后,是會打開一個Admob sdk中的AdActivity
,在AdActivity
中會處理一些邏輯,之后才會通過Intent打開Google Play或者瀏覽器,跳轉到落地頁。
?
如何爬坑
打開Admob的aar包中的AndroidManifest可以發現AdActivity
是沒有聲明進程的,無論在哪個進程打開Activity,都會在主進程打開這個Activity。
?
仔細想想,子進程中獲取到的廣告,在主進程中根本就沒有,AdActivity
是在主進程的,所以這樣的調用會被判斷為非法調用,最終無法打開落地頁。
?
最后使用了Activity的屬性,在AdActivity
中添加multiprocess="true"
的聲明,就可以解決這個問題,達到在哪個進程打開AdActivity
,AdActivity
就在哪個進程。
?
但是忠告一句,Admob SDK實際上原生并不支持在子進程獲取廣告,不排除這樣修改后,還會不會出現什么奇葩的問題。
?
何為multiprocess
官方定義
multiprocess
在activity和provider中都能定義。
android:multiprocess=["true" | "false"]
?
provider中的定義如下:
If the app runs in multiple processes, this attribute determines whether multiple instances of the content provder are created. If true, each of the app's processes has its own content provider object. If false, the app's processes share only one content provider object. The default value is false.
Setting this flag to true may improve performance by reducing the overhead of interprocess communication, but it also increases the memory footprint of each process.
在Provider中使用可能更為常見,簡單來說意思就是如果multiprocess為true,不管在哪個進程中調用provider將會使用該進程中的provider實例,并不會共用,如multiprocess為false,那么provider聲明在哪個進程,provider就只會在這個進程中存在實例。
?
activity中的定義如下:
Whether an instance of the activity can be launched into the process of the component that started it — "true" if it can be, and "false" if not. The default value is "false".
Normally, a new instance of an activity is launched into the process of the application that defined it, so all instances of the activity run in the same process. However, if this flag is set to "true", instances of the activity can run in multiple processes, allowing the system to create instances wherever they are used (provided permissions allow it), something that is almost never necessary or desirable.
Activity的話,和provider差不多意思。當聲明了multiprocess為true,那么在哪個進程中通過intent打開這個activity,這個activity就存在于哪個進程中。
?
multiprocess測試
進程測試
新建一個項目,創建幾個Activity,分別為
<activity
android:name=".MainActivity"
android:label="Main"
android:multiprocess="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
?
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
?
<activity
android:name=".SecondaryOneProcessActivity"
android:label="SecondaryOne"
android:process=":remote1" />
?
<activity
android:name=".SecondaryTwoProcessActivity"
android:label="SecondaryTwo"
android:process=":remote2" />
?
以上Activity繼承GetProcessActivity(代碼如下):
package org.purplek.multiprocesstest;
?
import android.app.ActivityManager;
import android.content.Intent;
import android.os.Bundle;
import android.os.Process;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
?
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
?
public abstract class GetProcessActivity extends AppCompatActivity {
?
@BindView(R.id.process)
TextView processTv;
?
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
?
processTv.setText("當前進程:" + getProcessName());
}
?
@OnClick(R.id.open_main)
public void openMain() {
startActivity(new Intent(this, MainActivity.class));
}
?
@OnClick(R.id.open_one)
public void openRemoteOne() {
startActivity(new Intent(this, SecondaryOneProcessActivity.class));
}
?
@OnClick(R.id.open_two)
public void openRemoteTwo() {
startActivity(new Intent(this, SecondaryTwoProcessActivity.class));
}
?
private String getProcessName() {
int pid = Process.myPid();
String processName = null;
ActivityManager mgr = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo appProcess : mgr.getRunningAppProcesses()) {
if (appProcess.pid == pid) {
processName = appProcess.processName;
break;
}
}
return processName;
}
}
?
?
在沒有使用multiprocess屬性的情況下,很明顯,各個Activity都會安分的只存在在聲明好的進程里。
?
?
?
現在嘗試修改一下AndroidManifest.xml,SecondaryTwoProcessActivity中添加multiprocess="true"
<activity
android:name=".MainActivity"
android:label="Main">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
?
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
?
<activity
android:name=".SecondaryOneProcessActivity"
android:label="SecondaryOne"
android:process=":remote1" />
?
<activity
android:name=".SecondaryTwoProcessActivity"
android:label="SecondaryTwo"
android:multiprocess="true"
android:process=":remote2" />
?
再運行一遍。
?
試著從以下路徑打開SecondaryTwoProcessActivity
(每個路徑執行之前都kill掉app重新打開MainActivity)
-
MainActivity
->SecondaryTwoProcessActivity
-
MainActivity
->SecondaryOneProcessActivity
->SecondaryTwoProcessActivity
-
MainActivity
->SecondaryOneProcessActivity
->MainActivity
->SecondaryTwoProcessActivity
?
結果分別如下:
?
?
可見,只要在哪個進程打開聲明了multiprocess="true"
的Activity,那么這個Activity就會在哪個進程,不會再收到android:process="xxxx"
的限制。
?
multiprocess對SingleInstance的影響
?
接下來再試試把AndroidManifest改成下面的樣子。
在SecondaryTwoProcessActivity
上添加launchMode="SingleInstance"
。
<activity
android:name=".MainActivity"
android:label="Main">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
?
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
?
<activity
android:name=".SecondaryOneProcessActivity"
android:label="SecondaryOne"
android:process=":remote1" />
?
<activity
android:name=".SecondaryTwoProcessActivity"
android:label="SecondaryTwo"
android:multiprocess="true"
android:launchMode="singleInstance"
android:process=":remote2" />
再定義幾個路徑來打開SecondaryTwoProcessActivity
看看結果如何。(每個路徑執行之前都kill掉app重新打開MainActivity)
-
MainActivity
->SecondaryTwoProcessActivity
->SecondaryOneProcessActivity
->SecondaryTwoProcessActivity
兩次打開SecondaryTwoProcessActivity
的結果都是在主進程。
?
-
MainActivity
->SecondaryOneProcessActivity
->SecondaryTwoProcessActivity
->MainActivity
->SecondaryTwoProcessActivity
?
兩次打開SecondaryTwoProcessActivity
的結果都是在remote1進程。
?
因此可以得出結論,當被聲明為multiprocess="true"
的Activity,再被添加上SingleInstance的時候,所屬進程就是在其還沒被打開時,第一個打開這個Activity的進程。
?
聲明SingleInstance + multiprocess="true"并沒有讓Activity在每個進程中SingleInstance,而是在第一個打開它的進程中存在,并保持App中所有進程內SingleInstance。