IPCInvoker,Android跨進程調用如此簡單

一個APP爲何須要多條進程?

若是一條進程可以擁有足夠多的資源,且不會被系統kill掉的話,讓程序運行在一條進程上是最好的選擇。可是系統資源是按進程來分配的,每條進程資源分配是有個上限的,並且當咱們的APP退到後臺以後,系統會根據系統資源使用狀況,回收部分後臺進程資源。java

具備推送或後臺播放音樂等功能的APP,在APP被退到後臺以後,爲了保持良好的用戶體驗,則須要在後臺保持運行狀態。而這些功能模塊的運行能夠脫離主程序而運行,爲了保持後臺運行,且不干預系統回收進程資源的前提下,咱們將這些功能拆分到小而獨立的進程當中。android

知足什麼條件才須要拆分獨立進程呢?git

  • 須要後臺保活的核心模塊;(如:Server push、後臺音樂播放或APP升級等)
  • 不穩定的新功能;(爲了避免影響主功能的正常使用,會選擇性的放到獨立進程中)
  • 部分佔用資源比較大的功能模塊;(如:WebView,圖庫等)

Android上有哪些跨進程通信方式?

在Android應用程序中跨進程通信是很是常見的,咱們經常使用的四大組件均支持跨進程通信。本文中咱們重點看下Service跨進程通信方式。github

Android提供的Service跨進程調用方式:框架

  • 經過AIDL定義跨進程接口調用跨進程邏輯;
  • 經過Messenger調用跨進程邏輯;

經過AIDL定義跨進程接口調用跨進程邏輯

經過AIDL定義跨進程接口提供給業務調用是Android應用程序開發中,最爲經常使用的跨進程調用實現的方式,AIDL接口提供了同步與異步調用的支持,基本能知足全部的跨進程調用需求。異步

經過AIDL接口調用跨進程邏輯須要以下幾個步驟:ide

  1. 鏈接Service;
  2. 等待Service鏈接成功後,持有鏈接遠端Service的Binder對象的引用;
  3. 經過Binder對象跨進程調用遠端邏輯;

代碼實現須要以下幾個步驟:函數

  1. 定義AIDL接口;
  2. 在Service端實現遠端接口邏輯;
  3. 在業務層中調用AIDL接口;

AIDL調用模型圖

經過Messenger調用跨進程邏輯

經過Messenger調用跨進程邏輯須要以下幾個步驟:post

  1. 鏈接Service;
  2. 等待Service鏈接成功後,將遠端Service的Binder對象綁定到Messenger上;
  3. 經過Messenger發送遠端調用Message,調用遠端進程邏輯;

代碼實現須要以下幾個步驟:ui

  1. 在Service端實現遠端接口邏輯;
  2. 在業務層中調用Messenger.send(Message)接口向遠端發出調用命令以實現跨進程調用;

Messenger調用模型圖

IPCInvoker如何調用跨進程邏輯

Android系統直接提供的AIDL和Messenger的方式存在的一些問題:

  • 調用一個跨進程接口時,須要理解Service的鏈接狀態;
  • 須要等待Service鏈接成功後,才能異步發起跨進程調用;
  • AIDL和Messenger的跨進程實現都是C/S的設計,跨進程邏輯須要預先寫在Service端,形成必定的代碼耦合問題;
  • 在超過2條進程的複雜進程調用模型中,寫跨進程代碼及其複雜;
  • 代碼邏輯不易維護;

最初設計IPCInvoker就是爲了解決AIDL和Messenger存在的問題,讓跨進程調用變得更簡單。下面咱們來看看IPCInvoker是如何作跨進程調用的。

IPCInvoker調用模型圖

從IPCInvoker調用模型圖中,能夠看出是AIDL的一個擴展,Service端做爲Task執行的容器,而由調用者來決定Task的邏輯實現。下面一塊兒看一下IPCInvoker的簡單使用。

同步調用跨進程邏輯

public class IPCInvokeSample_InvokeByType {

    private static final String TAG = "IPCInvokerSample.IPCInvokeSample_InvokeByType";

    public static void invokeSync() {
        Bundle bundle = new Bundle();
        bundle.putString("name", "AlbieLiang");
        bundle.putInt("pid", android.os.Process.myPid());
        IPCString result = IPCInvoker.invokeSync(PushProcessIPCService.PROCESS_NAME,
                    bundle, IPCRemoteInvoke_BuildString.class);
        Log.i(TAG, "invoke result : %s", result);
    }

    private static class IPCRemoteInvoke_BuildString implements IPCRemoteSyncInvoke<Bundle, IPCString> {

        @Override
        public IPCString invoke(Bundle data) {
            String msg = String.format("name:%s|fromPid:%s|curPid:%s",
                        data.getString("name"), data.getInt("pid"), android.os.Process.myPid());
            Log.i(TAG, "build String : %s", msg);
            return new IPCString(msg);
        }
    }
}
複製代碼

IPCInvoker實現跨進程調用主要分爲兩部分:

  • 示例中的IPCRemoteInvoke_BuildString類中的invoke函數的實現就是跨進程邏輯,這裏只是輸出了一行log,並把msg做爲返回值return了;
  • 示例中IPCString result = IPCInvoker.invokeSync(xxx)即是跨進程調用,這裏的調用把須要在遠端進程執行的邏輯的class做爲參數傳入了IPCInvoker。

看到上面示例代碼,是否是根本沒有感受到這是在寫跨進程代碼?也沒看到有鏈接Service的過程了!對的IPCInvoker設計的初衷就是讓跨進程調用變得簡單,就像Handler.post一個Runnable同樣簡單。

若是你們進一步思考上述示例中的代碼,並對比AIDL和Messenger的跨進程實現,能夠很明顯看出IPCInvoker的跨進程實現是高內聚的,跨進程邏輯不用寫在Service裏面,這樣業務邏輯就不用與Service產生任何的耦合了,Service在IPCInvoker框架中只是一個執行遠端邏輯的容器。

下面咱們在看一下IPCInvoker異步調用跨進程邏輯代碼是如何寫的

異步調用跨進程邏輯

public class IPCInvokeSample_InvokeByType {

    private static final String TAG = "IPCInvokerSample.IPCInvokeSample_InvokeByType";

    public static void invokeAsync() {
        Bundle bundle = new Bundle();
        bundle.putString("name", "AlbieLiang");
        bundle.putInt("pid", android.os.Process.myPid());
        IPCInvoker.invokeAsync(PushProcessIPCService.PROCESS_NAME, bundle,
                IPCRemoteInvoke_PrintSomething.class, new IPCRemoteInvokeCallback<IPCString>() {
            @Override
            public void onCallback(IPCString data) {
                Log.i(TAG, "onCallback : %s", data.value);
            }
        });
    }

    private static class IPCRemoteInvoke_PrintSomething implements IPCRemoteAsyncInvoke<Bundle, IPCString> {

        @Override
        public void invoke(Bundle data, IPCRemoteInvokeCallback<IPCString> callback) {
            String result = String.format("name:%s|fromPid:%s|curPid:%s",
                        data.getString("name"), data.getInt("pid"), android.os.Process.myPid());
            callback.onCallback(new IPCString(result));
        }
    }
}
複製代碼

異步調用是經過調用IPCInvoker.invokeAsync實現的,這個接口與IPCInvoker.invokeSync相比多了一個IPCRemoteInvokeCallback參數,IPCRemoteInvokeCallback的onCallback函數的回調依賴遠端邏輯的主動調用,onCallback能夠被屢次調用。

上面使用的是IPCInvoker中最爲基本和最簡單的兩個接口IPCInvoker.invokeSyncIPCInvoker.invokeAsync,能夠很明顯看出IPCInvoker相比普通的AIDL和Messenger實現的跨進程調用更爲直觀,接口更容易使用。

IPCInvoker組件裏面還包括了幾大模塊:

最後

到目前爲止本文還沒介紹如何接入IPCInvoker,其實IPCInvoker的接入也是很是簡單的,這裏就不展開說明了,你們能夠經過閱讀《接入IPCInvoker》來接入IPCInvoker。IPCInvoker的wiki文檔能夠到《IPCInvoker wiki》中詳細閱讀。

歡迎使用IPCInvoker,有興趣的同窗能夠一塊兒維護該項目。(項目地址爲github.com/AlbieLiang/…

相關文章
相關標籤/搜索