Binder双向通信4 ---- RemoteCallbackList

RemoteCallbackList 是 Android 提供的专门管理跨进程回调的容器。继续修改下RemoteService,使用RemoteCallbackList管理跨进程回调,替换掉那个ArrayList的callback容器。RemoteService代码如下:

java 复制代码
package com.example.binderdemo;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

public class RemoteService extends Service {
    private static final String TAG = "RemoteService";

//    private final List<ICallback> callbacks = new ArrayList<>();
    private final android.os.RemoteCallbackList<ICallback> callbacks =
            new android.os.RemoteCallbackList<>();

    private final android.os.Handler handler =
            new android.os.Handler(android.os.Looper.getMainLooper());

    private final Runnable tick = new Runnable() {
        @Override
        public void run() {
            int n = callbacks.beginBroadcast();
            Log.d(TAG, "tick, callbacks.size=" + n);
            Log.d(TAG, "tick, callbacks.size=" + n + ", 何以解忧,唯有退休?");
            try {
                for (int i = 0; i < n; i++) {
                    ICallback cb = callbacks.getBroadcastItem(i);
                    try {
                        cb.onResult(9527);
                    } catch (RemoteException e) {
                        Log.e(TAG, "tick onResult failed: " + e);
                    }
                }
            } finally {
                callbacks.finishBroadcast();
            }
            handler.postDelayed(this, 3000);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate, start tick");
        handler.postDelayed(tick, 3000);
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy, stop tick");
        handler.removeCallbacks(tick);
        super.onDestroy();
    }

    private final IMyAidlInterface.Stub binder = new IMyAidlInterface.Stub() {
        @Override
        public int add(int a, int b) throws RemoteException {
            Log.d(TAG, "add(" + a + "," + b + ") thread="
                    + Thread.currentThread().getName()
                    + ", pid=" + Process.myPid());

            int result = a + b;
            // 遍历回调:beginBroadcast / getBroadcastItem / finishBroadcast
            int n = callbacks.beginBroadcast();
            try {
                for (int i = 0; i < n; i++) {
                    ICallback cb = callbacks.getBroadcastItem(i);
                    try {
                        cb.onResult(result);
                    } catch (RemoteException e) {
                        Log.e(TAG, "onResult failed: " + e);
                    }
                }
            } finally {
                callbacks.finishBroadcast();
            }

            return result;
        }

        @Override
        public String getMessage() {
            Log.d(TAG, "getMessage thread="
                    + Thread.currentThread().getName()
                    + ", pid=" + Process.myPid());
            return "Hello from pid=" + Process.myPid() + " , 为人不识陈近南,纵称英雄也枉然。";
        }

        @Override
        public void registerCallback(ICallback cb) throws RemoteException {
            if (cb == null) return;
            Log.d(TAG, "registerCallback cb=" + cb
                    + ", class=" + cb.asBinder().getClass().getName()
                    + ", thread=" + Thread.currentThread().getName());
            callbacks.register(cb);
        }

        @Override
        public void unregisterCallback(ICallback cb) throws RemoteException {
            if (cb != null) {
                callbacks.unregister(cb);
            }
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind thread="
                + Thread.currentThread().getName()
                + ", pid=" + Process.myPid());
        return binder;
    }
}

运行,查看日志:

点击杀客户端进程按钮,日志:

可以看出,使用RemoteCallbackList管理callback比较方便,其内部还兼顾了线程同步。而且客户端进程被杀掉后,服务端自动清理callback。callbacks.size 自动变 0,不需要写 binderDied,RemoteCallbackList 内部已经 linkToDeath 了。没有任何 DeadObjectException,因为死回调在 tick 遍历之前已经被移除了。没有 ConcurrentModificationException,beginBroadcast / finishBroadcast 的遍历快照机制生效了。onDestroy 在 60 秒后出现,这是后台服务限制,和 Binder 无关。比手动维护一个callback数组很有优势。

ok.

相关推荐
zh_xuan2 天前
Binder双向通信实验2 ---- 客户端死亡, 看服务端是否能正常调用callback
binder·deadobject
消失的旧时光-19431 个月前
Android 系统层扫盲 11:JNI 到底是什么?Java / Kotlin 是怎么调用 C/C++ 的?
android·binder·zygote·system_server·aops
wardenlzr2 个月前
车机Binder 线程池耗尽实战排查与内核内存原理深挖
binder·性能·车机
Android-Flutter2 个月前
android Binder 应用层开发 详解
android·binder
爱跑马的程序员2 个月前
安卓专有的通信子系统-Binder IPC
android·binder·ipc·安卓间通信机制
tzc_fly2 个月前
KDD 2026 | PRIME:一种用于从头设计binder的 3D 分子模型
3d·binder
且随疾风前行.3 个月前
Android Binder 驱动 - 内核驱动层源码初探
android·网络·binder
故渊at4 个月前
第十一板块:Android 跨进程通信与 Binder 深度剖析 | 第二十七篇:Binder 线程池与死亡通知(Death Recipient)机制
android·binder·线程池·死亡通知·跨进程通讯
故渊at4 个月前
第二板块:Android 四大组件标准化学理 | 第十一篇:组件间通信(IPC)与 Binder 深度解析
android·binder·组件化·组件间通信