Activity中的multiprocess="true"??

坑的背景

在下是一個小小的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)

  1. MainActivity -> SecondaryTwoProcessActivity
  2. MainActivity -> SecondaryOneProcessActivity -> SecondaryTwoProcessActivity
  3. 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。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,359評論 25 708
  • 1.什么是Activity?問的不太多,說點有深度的 四大組件之一,一般的,一個用戶交互界面對應一個activit...
    JoonyLee閱讀 5,760評論 2 51
  • Application 標簽 android:allowTaskReparenting android:allow...
    Shawn_Dut閱讀 7,918評論 2 61
  • 秋風起,人腳癢,以蟹名,出去浪。 又到了一年一度的吃蟹季節。 這邊講究陽澄湖大閘蟹,我們又離陽澄湖不遠。 所以我和...
    S貓閱讀 597評論 3 4
  • 育氣調精徒費力,鴻蒙拊脾任浮游。 為國為眾失心養,無欲無求有自由。 忘相隳形天地友,遷德淫性志情仇。 六極四海獨來...
    陶然忘機閱讀 274評論 0 0