中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何實現CmProcess跨進程通信

發布時間:2021-06-28 14:22:47 來源:億速云 閱讀:191 作者:小新 欄目:開發技術

這篇文章給大家分享的是有關如何實現CmProcess跨進程通信的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

一、基礎知識準備

1.1、多進程

Android多進程概念:一般一個 app 只有一個進程,所有的 components 都運行在同一個進程中,進程名稱就是 app 包名。但是每一個進程都有內存的限制,如果一個進程的內存超過了這個限制的時候就會報 OOM 錯誤。為了解決內存限制的問題,Android 引入了多進程的概念,將占用內存的操作放在一個單獨的進程中分擔主進程的壓力。

多進程的好處:

  • 分擔主進程的內存壓力。

  • 常駐后臺任務。

  • 守護進程,主進程和守護進程相互監視,有一方被殺就重新啟動它。

  • 多么塊,對有風險的模塊放在單獨進程,崩潰后不會影響主進程的運行。

多進程的缺點:

  • Applicaton的重新創建,每個進程有自己獨立的virtual machine,每次創建新的進程就像創建一個新的Application

  • 靜態成員變量和單例模式失效,每個進程有自己獨立的虛擬機,不同虛擬機在內存分配上有不同的地址空間,這就導致不同虛擬機在訪問同一個對象時會產生多分副本。

  • SharedPreference的可靠性下降,不支持多進程

  • 線程同步機制失效

1.2、Bundle類

bundle 定義 bundle 是一個 final 類,final 類通常功能是完整的,它們不能被繼承。Java 中有許多類是 final 的,譬如 String, Interger 以及其他包裝類。

public final class Bundle extends BaseBundle implements Cloneable, Parcelable

bundle 傳遞的數據可以是 boolean、byte、int、long、float、double、string 等基本類型或它們對應的數組,也可以是對象或對象數組。但是如果傳遞對象或對象數組,該對象必須實現 Serializable 或 Parcelable 接口。由 Bundle 定義我們也可以看到其實現了 Parcelable 接口,所以支持實現了Parcelable 接口的對象。
因此當我們在一個進程中啟動了另外一個進程的 Activity、Service、Receiver,我們就可以在 Bundle 中附加我們需要傳輸給遠程進程的信息(前提是能夠被序列化)并通過 Intent 發送出去。

二、代碼解析

2.1、AIDL接口

1、IEventReceiver:事件接收器

// 事件接受器
interface IEventReceiver {
   // 這里的 event 是 bundle 類型
    void onEventReceive(String key,in Bundle event);
}

2、IPCCallback:看名字也可以看出來是跨進程 callback

interface IPCCallback {
   // result 也是 bundle
    void onSuccess(in Bundle result);
    void onFail(String reason);
}

3、IServiceFetcher:獲取服務的。可以再此進行注冊。

interface IServiceFetcher {   // service 是 Ibinder 類型
    android.os.IBinder getService(java.lang.String name);   // 注冊服務
    void addService(java.lang.String name, android.os.IBinder service);   // 添加回調
    void addEventListener(java.lang.String name, android.os.IBinder service);   // 移除 service 
    void removeService(java.lang.String name);   // 移除回調
    void removeEventListener(java.lang.String name);  // 發送消息
    void post(String key,in Bundle result);
}

2.2、啟動分析

根據代碼可知,咱們有三個進程,分別是:

  • com.ipc.code:vc :TestActivity 運行所在的進程;這是屬于用戶測的。

  • com.ipc.code:vm : 也就是BinderProvider 存在的進程;IPCBus 也在該進程,主要是用于保存和傳遞數據

  • com.ipc.code :MainActivity 主進程;

也就是每個進程在初始化的時候,都會走一遍Application 的初始化,因此如果需要對進程做啥操作,可以判斷出具體的進程,然后做一些額外的操作。對于 CmProcess ,所有進程的初始化邏輯都是一樣的。

public class App extends Application {
    private static final String TAG = "App";

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        // 先啟動主進程,之后才啟動其他進程
        VCore.init(base);
    }
}

啟動過程中,會主動為每個進程注冊回調,注意是每個進程。

該 init 方法最終會走入到下面的方法中:

public void startup(Context context) {
        if (!isStartUp) {
            // 在主線程啟動,每個進程都有一個自己的主線程
            if (Looper.myLooper() != Looper.getMainLooper()) {
                throw new IllegalStateException("VirtualCore.startup() must called in main thread.");
            }

            ServiceManagerNative.SERVICE_CP_AUTH = context.getPackageName() + "." + ServiceManagerNative.SERVICE_DEF_AUTH;
            this.context = context;
            // 傳入了一個 cache 實例,這個實例是只有主線程有的
            IPCBus.initialize(new IServerCache() {
                @Override
                public void join(String serverName, IBinder binder) {
                    ServiceManagerNative.addService(serverName, binder);
                }

                @Override
                public void joinLocal(String serverName, Object object) {
                    ServiceCache.addLocalService(serverName,object);
                }

                @Override
                public void removeService(String serverName) {
                    ServiceManagerNative.removeService(serverName);
                }

                @Override
                public void removeLocalService(String serverName) {
                     ServiceCache.removeLocalService(serverName);
                }

                @Override
                public IBinder query(String serverName) {
                    return ServiceManagerNative.getService(serverName);
                }

                @Override
                public Object queryLocal(String serverName) {
                    return ServiceCache.getLocalService(serverName);
                }

                @Override
                public void post(String key,Bundle bundle) {
                    ServiceManagerNative.post(key,bundle);
                }
            });       // 這里是根據進程名字添加注冊的事件接收器
            ServiceManagerNative.addEventListener(AppUtil.getProcessName(context, Process.myPid()), EventReceiver.getInstance());
            isStartUp = true;
        }
    }

這里整個邏輯很簡單,就是在主線程初始化了IPCBus,然后給該進程注冊了一個事件分發的監聽。

三、EventReceiver

public class EventReceiver extends IEventReceiver.Stub {

    private static final String TAG = "EventReceiver";

    private static final EventReceiver EVENT_RECEIVER = new EventReceiver();

    private EventReceiver(){}

    public static final EventReceiver getInstance(){
        return EVENT_RECEIVER;
    }

    @Override
    public void onEventReceive(String key,Bundle event) {
        EventCenter.onEventReceive(key,event);
    }
}

整個類的代碼很簡單。但是要注意的是,其繼承了IEventReceiver.Stub,說明他具有跨進程傳輸的能力。主要就是通過EventCenter 來分發消息。

由于每個進程都會走一遍初始化邏輯,所以每個進程都注冊了事件的接收。

四、ServiceManagerNative

從名字也可以看出來,這個跟我們平時看到的ServiceManager 很像。主要就是用來獲取 service 和注冊 listener 的。

public static void addEventListener(String name, IBinder service) {
    IServiceFetcher fetcher = getServiceFetcher();
    if (fetcher != null) {
        try {
            fetcher.addEventListener(name, service);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

首先是調用getServiceFetcher 來獲取最終保存服務的 fetcher。

注冊回調的時候,會先獲取是否存在 (binder)ServiceFetcher ,在將其轉化為本地 binder;這樣 ServiceFetcher 的管理器就可以用了。

private static IServiceFetcher getServiceFetcher() {
    if (sFetcher == null || !sFetcher.asBinder().isBinderAlive()) {
        synchronized (ServiceManagerNative.class) {
            Context context = VirtualCore.get().getContext();
            Bundle response = new ProviderCall.Builder(context, SERVICE_CP_AUTH).methodName("@").call();
            if (response != null) {
                IBinder binder = BundleCompat.getBinder(response, "_VM_|_binder_");
                linkBinderDied(binder);
                sFetcher = IServiceFetcher.Stub.asInterface(binder);
            }
        }
    }
    return sFetcher;
}

首先是看ProviderCall.Builder(context, SERVICE_CP_AUTH).methodName("@").call(),他最終會調用下面的方法:

//ContentProviderCompat
public static Bundle call(Context context, Uri uri, String method, String arg, Bundle extras) {
    // 這里還區分了版本
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
        return context.getContentResolver().call(uri, method, arg, extras);
    }
    ContentProviderClient client = crazyAcquireContentProvider(context, uri);  // 這里會不斷重試最終會獲得對 BinderProvider 的引用
    Bundle res = null;
    try {
        // 通過約定好的方法名字獲得bindle
        res = client.call(method, arg, extras);
    } catch (RemoteException e) {
        e.printStackTrace();
    } finally {
        releaseQuietly(client);
    }
    return res;
}

五、BinderProvider

下面看下 BinderProvider 的 call 方法。

新建了一個 bundle 對象,然后將 binder 保存在里面。注意這是通過跨進程調用,最終將 bundle 傳回主進程,然后拿到了ServiceFetcher 的 binder,并將其轉為本地 binder。

可以發現這里對于方法名是 "@" 時,就會返回 bundle ,否則就是返回 null 。

public Bundle call(String method,  String arg,  Bundle extras) {
    if ("@".equals(method)) {
        Bundle bundle = new Bundle();
        BundleCompat.putBinder(bundle, "_VM_|_binder_", mServiceFetcher);
      return bundle;
    }
    return null;
}

簡單來說,就是大家都通過 binderProvider 這個進程來保存對于回調的注冊,保存是基于進城名字來的,因此可以保證不會被覆蓋。

此處的mServiceFetcher 是BinderProvider 內部內的實例,但是其繼承了IServiceFetcher.Stub,因此也就有了跨進程的能力。

到這里,理一下前面的邏輯:

ServiceManagerNative.addEventListener(AppUtil.getProcessName(context, Process.myPid()), EventReceiver.getInstance());

某個進程的主線程調用這個方法,所做的具體事情如下:

1.通過 binder 拿到了binderProvider 中的 IServiceFetcher.Stub 的實例;

2.向IServiceFetcher.Stub 注冊回調,該回調最終會被保存binderProvider 進程里面。

六、BinderProvider 啟動分析

上面介紹了其是怎么將 listener 注冊到 binderProvider 進程的,但是并沒有講到接下去我們看下 BinderProvider 的啟動過程,

下圖是ContentProvider 的啟動流程。當我們在主進程想獲取 server 的時候,這時候,會看看 provider 存不存在,沒有的就會進行啟動,同時會走 Application 的初始化邏輯,

如何實現CmProcess跨進程通信

具體我們可以看下面這個啟動流程圖:

如何實現CmProcess跨進程通信

  • Application 的 attachBaseContext 方法是優先執行的;

  • ContentProvider 的 onCreate的方法 比 Application的onCreate的方法先執行;

  • Activity、Service 的 onCreate 方法以及 BroadcastReceiver 的 onReceive 方法,是在 MainApplication 的 onCreate 方法之后執行的;

  • 調用流程為: Application 的 attachBaseContext ---> ContentProvider 的 onCreate ----> Application 的 onCreate ---> Activity、Service 等的 onCreate(Activity 和 Service 不分先后);

這里主要是梳理了下 provider 的啟動過程,并沒有很細講,但是有必要了解一下。

七、MainActivity

接下去,開始看MainActivity 里面的代碼。

調用registerService 注冊服務,傳入IPayManager.class 和MainActivity;記得MainActivity 也實現了IPayManager 接口。

VCore.getCore().registerService(IPayManager.class, this);

看下,里面的具體代碼邏輯

// Vcore
public VCore registerService(Class<?> interfaceClass, Object server){
    if (VirtualCore.get().getContext() == null){
        return this;
    }
    Object o = IPCBus.getLocalService(interfaceClass);
    // 如果是第一次調用就會返回空
    IBinder service = ServiceManagerNative.getService(interfaceClass.getName());  
    if (service != null && o != null){
        return this;
    }
    IPCBus.registerLocal(interfaceClass,server);
    // 這里的注冊就是把 server 保存到 binder 中
    IPCBus.register(interfaceClass,server);
    return this;
}

這里使用了一個registerLocal和register 方法,但是本質上兩個方法是有區別的。registerLocal 意思很明確,就是本地ServiceCache保存一份。但是register,確實做了一些額外的操作。

public static void register(Class<?> interfaceClass, Object server) {
    checkInitialized();
    // 這里主要是獲取一個 binder,或者換句話來說,采用 binder 來保存相關數據
    ServerInterface serverInterface = new ServerInterface(interfaceClass);
    // 這里就是把 binder 保存到 binderProvider
    TransformBinder binder = new TransformBinder(serverInterface, server);
    sCache.join(serverInterface.getInterfaceName(), binder);
}

首先這里創建了一個ServerInterface 實例,該實例內部保存了傳過了來的接口和接口的方法,并將方法和 code 聯系在一起。

public ServerInterface(Class<?> interfaceClass) {
    this.interfaceClass = interfaceClass;
    Method[] methods = interfaceClass.getMethods();
    codeToInterfaceMethod = new SparseArray<>(methods.length);
    methodToIPCMethodMap = new HashMap<>(methods.length);
    for (int i = 0; i < methods.length; i++) {// 這里每一個方法都有一個 code 
        int code = Binder.FIRST_CALL_TRANSACTION + i;// 組成一個 ipcMenhod
        IPCMethod ipcMethod = new IPCMethod(code, methods[i], interfaceClass.getName());
        codeToInterfaceMethod.put(code, ipcMethod);// 保存他們的映射關系
        methodToIPCMethodMap.put(methods[i], ipcMethod);
    }
}

同時利用TransformBinder 將接口和 實例保存到 binder 中。再將 binder 和 接口名字 保存到ServiceCache 中。

注冊完以后,下面是調用獲取本地服務:

// 其實 service 本質還是這個 MainActivity
IPayManager service = VCore.getCore().getLocalService(IPayManager.class);

最后注冊了一個回調:

VCore.getCore().subscribe("key", new EventCallback() {
    @Override
    public void onEventCallBack(Bundle event) {

    }
});

最終EventCenter 會保存相關信息;

八、TestActivity

最后啟動 TestActivity ,這個是在另一個進程。在 onCreate 里面調用下面的方法:

IPayManager service = VCore.getCore().getService(IPayManager.class);

進程剛剛創建,我們看看是怎么獲取服務的:

// Vcore 
public <T> T getService(Class<T> ipcClass){
    T localService = IPCBus.getLocalService(ipcClass);
    if (localService != null){
        return localService;
    }
    return VManager.get().getService(ipcClass);
}

這里很明確,本地肯定是沒有的,因此,最后會從 VManager 中獲取:

// VManager
public <T> T getService(Class<T> ipcClass) {
    T t = IPCBus.get(ipcClass);
    if (t != null){
        return t;
    }
    IPCSingleton<T> tipcSingleton = mIPCSingletonArrayMap.get(ipcClass);
    if (tipcSingleton == null){
        tipcSingleton = new IPCSingleton<>(ipcClass);
        mIPCSingletonArrayMap.put(ipcClass,tipcSingleton);
    }
    return tipcSingleton.get();
}

接下去我們看下IPCSingleton 相關邏輯

// IPCSingleton
public T get() {
    if (instance == null) {
        synchronized (this) {
            if (instance == null) {
                instance = IPCBus.get(ipcClass);
            }
        }
    }
    return instance;
}

這是一個單例,目的也很明確,就是只獲取一次,可以看到后面又調到了 IPCBus 里面。

//   IPCBus
public static <T> T get(Class<?> interfaceClass) {
    checkInitialized();
    ServerInterface serverInterface = new ServerInterface(interfaceClass);
    // 這里獲取的 binder 應該是 TransformBinder
    IBinder binder = sCache.query(serverInterface.getInterfaceName());
    if (binder == null) {
        return null;
    }
    // 這里使用了動態代理
    return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new IPCInvocationBridge(serverInterface, binder));
}

這里采用了動態代理創造了一個實例,最終返回的實例被保存在一個單例中。

可以看到,這里回去查找存不存在 binder。

// VirtualCore
public IBinder query(String serverName) {
      return ServiceManagerNative.getService(serverName);
}

還是通過ServiceManagerNative 來獲取的 service;這里又回到我們之前分析過的邏輯。先從 binderProvider 獲取fetcher, 也就是 ServiceFetcher。

IServiceFetcher fetcher = getServiceFetcher();

它也會從ServiceFetcher 中獲取到 binder ,而這個 binder 就是之前我們保存的TransformBinder 。拿到這個之后,還是一樣,將其轉化為該進程的本地 binder .

 // BinderProvider
 private class ServiceFetcher extends IServiceFetcher.Stub {

最后,我們通過動態代理的形式,創建了一個 IPayManager 的實例。

return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new IPCInvocationBridge(serverInterface, binder));

這里需要注意的是IPCInvocationBridge 繼承自InvocationHandler。

拿到后,開始調用對應的方法:

if (service != null){
    Log.d(TAG, "onCreate: shentest  before   vcore   " + AppUtil.getAppName(this));
    // 首先這個 service 是跨進程調用的,怎么才通知到其他組件?這里大家可以思考下
    service.pay(5000, new BaseCallback() {
        @Override
        public void onSucceed(Bundle result) {
            textview.setText(result.getString("pay"));
            Bundle bundle = new Bundle();
            bundle.putString("name", "DoDo");
            VCore.getCore().post("key",bundle);
        }

        @Override
        public void onFailed(String reason) {

        }
    });
}

調用 service.pay 的時候,就會調用動態代理中的 invoke 方法:

public Object invoke(Object o, Method method, Object[] args) throws Throwable {
    IPCMethod ipcMethod = serverInterface.getIPCMethod(method);
    if (ipcMethod == null) {
        throw new IllegalStateException("Can not found the ipc method : " + method.getDeclaringClass().getName() + "@" +  method.getName());
    }     // 這里很關鍵
    return ipcMethod.callRemote(binder, args);
}

首先根據方法名獲得ipcMethod,里面保存了方法的 code,接口名字,參數,返回值。接著調用了 ipcMethod.callRemote, 該方法又會調用:

// IPCMethod 
// 這個方法很重要,需要理解其實現過程
public Object callRemote(IBinder server, Object[] args) throws RemoteException {
    Parcel data = Parcel.obtain(); // 獲取一個新的 parcel 對象
    Parcel reply = Parcel.obtain();
    Object result;
    try {
        data.writeInterfaceToken(interfaceName);
        data.writeArray(args);       // 這里 server 就是 transformBinder
        server.transact(code, data, reply, 0);
        reply.readException();
        result = readValue(reply);
        if (resultConverter != null) {
            result = resultConverter.convert(result);
        }
    } finally {
        data.recycle();
        reply.recycle();
    }
    return result;
}

code 變量用于標識客戶端期望調用服務端的哪個函數,因此,雙方需要約定一組 int 值,不同的值代表不同的服務端函數,該值和客戶端的 transact() 函數中第一個參數 code 的值是一致的。

enforceInterface() 是為了某種校驗,它與客戶端的 writeInterfaceToken() 對應,具體見下一小節。
readString() 用于從包裹中取出一個字符串。如果該 IPC 調用的客戶端期望返回一些結果,則可以在返回包裹 reply 中調用 Parcel 提供的相關函數寫入相應的結果。 Parcel.writeXXX();

現在要看的是怎么通過 binder 一步一步拿到參數。

使用 Parcel 一般是通過 Parcel.obtain() 從對象池中獲取一個新的 Parcel 對象,如果對象池中沒有則直接 new 的 Parcel 則直接創建新的一個 Parcel 對象,并且會自動創建一個Parcel-Native 對象。

writeInterfaceToken 用于寫入 IBinder 接口標志,所帶參數是 String 類型的,如 IServiceManager.descriptor = "android.os.IServiceManager"。

之前說的 code 在這里用上了,code 是一個私有變量,跟 method 綁定在一起的。

中間有個 server.transact(code, data, reply, 0); 該方法實現了跨進程調用,最終會走到 binderProvider 的下面onTransact方法:

// TransformBinder 運行在主進程
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {     // 回調進來后,就到了  MainActivity 的進程
    if (code == INTERFACE_TRANSACTION) {
        reply.writeString(serverInterface.getInterfaceName());
        return true;
    }
    IPCMethod method = serverInterface.getIPCMethod(code);
    if (method != null) {
        try {
            method.handleTransact(server, data, reply);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return true;
    }
    return super.onTransact(code, data, reply, flags);
}

這里主要是根據 code 來獲取到是哪個方法被調用了,下面才是真正的處理。

// IPCMethod 
public void handleTransact(Object server, Parcel data, Parcel reply) {
    data.enforceInterface(interfaceName); // 確保是目標接口
    Object[] parameters = data.readArray(getClass().getClassLoader());
    if (parameters != null && parameters.length > 0) {
        for (int i = 0; i < parameters.length; i++) {
            if (converters[i] != null) {
                parameters[i] = converters[i].convert(parameters[i]);
            }          // 如果參數里面包含有 binder 
            if (parameters[i] instanceof IBinder){
                parameters[i] = IPCCallback.Stub.asInterface(((IBinder)parameters[i]));
            }
        }
    }
    try {
        // 最終通過反射的形式實現了的調用
        // 其實最主要的是通過 binder 拿到參數,然后知道對方調用的是哪個方法。
        // 現在要分析的是,他怎么將數據傳過來的
        Object res = method.invoke(server, parameters);
        reply.writeNoException();
        reply.writeValue(res);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
        reply.writeException(e);
    } catch (InvocationTargetException e) {
        e.printStackTrace();
        reply.writeException(e);
    }
}

看看 convert 里面的操作:

public Object convert(Object param) {
    if (param != null) {
        if (asInterfaceMethod == null) {
            synchronized (this) {
                if (asInterfaceMethod == null) {                 // 找到 asInterface 方法
                    asInterfaceMethod = findAsInterfaceMethod(type);
                }
            }
        }
        try {            // 因為 asInterface 方法是靜態方法,所以對象可以傳入空,最終轉變成所需要的參數類型
            return asInterfaceMethod.invoke(null, param);
        } catch (Throwable e) {
            throw new IllegalStateException(e);
        }
    }
    return null;
}

通過 convert 這個一調用,就轉變成我們所需要的參數了。

private static Method findAsInterfaceMethod(Class<?> type) {
    for (Class<?> innerClass : type.getDeclaredClasses()) {
        // public static class Stub extends Binder implements IType
        if (Modifier.isStatic(innerClass.getModifiers())
                && Binder.class.isAssignableFrom(innerClass)
                && type.isAssignableFrom(innerClass)) {
            // public static IType asInterface(android.os.IBinder obj)
            for (Method method : innerClass.getDeclaredMethods()) {
                if (Modifier.isStatic(method.getModifiers())) {
                    Class<?>[] types = method.getParameterTypes();
                    if (types.length == 1 && types[0] == IBinder.class) {
                        return method;
                    }
                }
            }
        }
    }
    throw new IllegalStateException("Can not found the " + type.getName() + "$Stub.asInterface method.");
}

findAsInterfaceMethod 通過層層篩選,最終獲得需要的那個方法:

public static com.cmprocess.ipc.server.IPCCallback com.cmprocess.ipc.server.IPCCallback$Stub.asInterface(android.os.IBinder)

通過 invoke 方法,終將獲得了我們需要的類型。

這里 server 就是 mainActivity。在把對應的參數傳進去即可。最終調到了mainActivity 里面的 pay 方法。

public void pay(final int count, final IPCCallback callBack) {

    new Thread(new Runnable() {
        @Override
        public void run() {
            SystemClock.sleep(2000);
            Bundle bundle = new Bundle();
            bundle.putString("pay", count + 100 + "");
            try {
                // callback 也是一個binder
                callBack.onSuccess(bundle);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

此處,callback 也是一個binder,調用成功后,發送了post。 其實最終也是調用了ServiceFetcher 。

// TestActivity
 VCore.getCore().post("key",bundle);

其實也是通過 binder 來進行發送消息的。由于每個進程都注冊了消息回調,因此,每個進程都會收到。

// ServiceCache
public static synchronized void sendEvent(String key,Bundle event){
    if (sEventCache.isEmpty()){
        return;
    }
    for (IBinder binder:sEventCache.values()){
        IEventReceiver eventReceiver = IEventReceiver.Stub.asInterface(binder);
        try {
            eventReceiver.onEventReceive(key, event);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

EventReceiver 存在于每個進程,因此,對于 binderprovider 來說都是客戶端,其他進程則是服務端。最終 EventCenter 會根據 KEY 值來做分發。

到這里整個流程就基本講完了。

不過我們發現還有兩個 service ,他們的作用是干嘛用的呢?感覺是用來保活的,防止 provider 死了。

感謝各位的閱讀!關于“如何實現CmProcess跨進程通信”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節
推薦閱讀:
  1. BitMap實現
  2. listview實現

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

迁西县| 海淀区| 梁山县| 曲松县| 安徽省| 宜宾市| 普宁市| 福清市| 象山县| 资阳市| 乌拉特后旗| 遂平县| 祁东县| 普兰店市| 八宿县| 望都县| 陕西省| 龙江县| 保亭| 永仁县| 曲周县| 丰顺县| 且末县| 清远市| 历史| 马龙县| 山阴县| 高安市| 湾仔区| 廉江市| 阳谷县| 独山县| 普宁市| 芮城县| 红桥区| 平凉市| 南江县| 穆棱市| 黔江区| 响水县| 玉门市|