aidl 回调 RemoteCallbackList

当用aidl方式实现监听回调时,Binder会吧传递过来的对象转化并生成一个新的对象,虽说我们register和unregister是同一个,但是传过来会变成两个对象,也就是找不到一开始register的对象,因此使用RemoteCallbackList。
IPowerStateListener为aidl定义的callback
onPowerStateChanged为callback里的方法

register(listener)   // IPowerStateListener listener
unregister(listener);

RemoteCallbackList 主要作用是可以把多个callback保存到列表里,在合适的时机同时回调,也可以防止重复的调用相同的 任务,只保证你需要的一个结果回调,它的源码也非常的简单:

package android.os;

import android.util.ArrayMap;
import android.util.Slog;

import java.io.PrintWriter;
import java.util.function.Consumer;

/**
 * 擅长 简单的持续性的一系列的远程接口的使用,尤其是Service对他的客户端的回调。
 * 需要注意的是:
 * 使用的时候,请确保每一个注册的callback唯一性,这样可以在进程停止的时候,清空这些callback。
 * 多线程请注意锁的问题。
 * 
 * 使用这个类只要在Service使用单例模式就可以了,使用register和unregister方法来添加客户端的回调,使用时,先beginBroadcast,在getBroadcastItem,最后finishBroadcast。
 * 
 * 如果一个注册的会滴啊进程结束了,这个类将自动从列中中移除,如果你想做一些额外的工作,就通过继承来实现onCallbackDied方法。
 * 
/
public class RemoteCallbackList<E extends IInterface> {
    /*package*/ ArrayMap<IBinder, Callback> mCallbacks
            = new ArrayMap<IBinder, Callback>();
    private Object[] mActiveBroadcast;
    private int mBroadcastCount = -1;
    private boolean mKilled = false;

    private final class Callback implements IBinder.DeathRecipient {
        final E mCallback;
        final Object mCookie;

        Callback(E callback, Object cookie) {
            mCallback = callback;
            mCookie = cookie;
        }

        public void binderDied() {
            synchronized (mCallbacks) {
                mCallbacks.remove(mCallback.asBinder());
            }
            onCallbackDied(mCallback, mCookie);
        }
    }

    /**
     * 注册方法
     */
    public boolean register(E callback) {
        return register(callback, null);
    }
    /**
     *注册的具体实现方法,注册的callback,只有在调用unregister或者进程结束才会被解绑,返回添加到集合中的结果(true、false)
     */
    public boolean register(E callback, Object cookie) {
        synchronized (mCallbacks) {
            if (mKilled) {
                return false;
            }
            IBinder binder = callback.asBinder();
            try {
                Callback cb = new Callback(callback, cookie);
                binder.linkToDeath(cb, 0);
                mCallbacks.put(binder, cb);
                return true;
            } catch (RemoteException e) {
                return false;
            }
        }
    }

    /**
     * 解绑callback
     */
    public boolean unregister(E callback) {
        synchronized (mCallbacks) {
            Callback cb = mCallbacks.remove(callback.asBinder());
            if (cb != null) {
                cb.mCallback.asBinder().unlinkToDeath(cb, 0);
                return true;
            }
            return false;
        }
    }

    /**
     * 清空之前所有注册的callback
     */
    public void kill() {
        synchronized (mCallbacks) {
            for (int cbi=mCallbacks.size()-1; cbi>=0; cbi--) {
                Callback cb = mCallbacks.valueAt(cbi);
                cb.mCallback.asBinder().unlinkToDeath(cb, 0);
            }
            mCallbacks.clear();
            mKilled = true;
        }
    }

    /**
     * 老版本的onCallbackDied
     */
    public void onCallbackDied(E callback) {
    }

    /**
     * 默认调用的是onCallbackDied(E callback)r
     */
    public void onCallbackDied(E callback, Object cookie) {
        onCallbackDied(callback);
    }

    /**
     * 开始对保存的集合进行回调,返回目前回调集合的大小
     */
    public int beginBroadcast() {
        synchronized (mCallbacks) {
            if (mBroadcastCount > 0) {
                throw new IllegalStateException(
                        "beginBroadcast() called while already in a broadcast");
            }

            final int N = mBroadcastCount = mCallbacks.size();
            if (N <= 0) {
                return 0;
            }
            Object[] active = mActiveBroadcast;
            if (active == null || active.length < N) {
                mActiveBroadcast = active = new Object[N];
            }
            for (int i=0; i<N; i++) {
                active[i] = mCallbacks.valueAt(i);
            }
            return N;
        }
    }

    /**
     * 获取指定索引的callback
     */
    public E getBroadcastItem(int index) {
        return ((Callback)mActiveBroadcast[index]).mCallback;
    }

    /**
     * 回去指定索引的callback的Cookie
     */
    public Object getBroadcastCookie(int index) {
        return ((Callback)mActiveBroadcast[index]).mCookie;
    }

    /**
     * 清楚之前的beginBroadcast的初始状态,当处理结束请调用这个方法。
     *
     * @see #beginBroadcast
     */
    public void finishBroadcast() {
        synchronized (mCallbacks) {
            if (mBroadcastCount < 0) {
                throw new IllegalStateException(
                        "finishBroadcast() called outside of a broadcast");
            }

            Object[] active = mActiveBroadcast;
            if (active != null) {
                final int N = mBroadcastCount;
                for (int i=0; i<N; i++) {
                    active[i] = null;
                }
            }

            mBroadcastCount = -1;
        }
    }

    /**
     * 返回当前的的要处理的callback数量
     * beginBroadcast 返回的是当前注册的数量
     * getRegisteredCallbackCount返回的是处理的数量
     * 两者的返回结果可能不同
     */
    public int getRegisteredCallbackCount() {
        synchronized (mCallbacks) {
            if (mKilled) {
                return 0;
            }
            return mCallbacks.size();
        }
    }
}

RemoteCallBackList 并不是一个List,不能像List一样去操作他,遍历RemoteCallBackList必须使用一下面方式进行,其中beginBroadcast和finishBroadcast必须配套使用,哪怕我们只想要获取RemoteCallBackList中的元素个数:
IPowerStateListener为aidl定义的callback
onPowerStateChanged为callback里的方法

int n = mPSListeners.beginBroadcast();
Log.d(TAG, "mPSListeners.beginBroadcast(): "+ n);
try {
    for(int i = 0; i < n; i++) {
        IPowerStateListener pslistener = mPSListeners.getBroadcastItem(i); 
        if(pslistener != null){
            pslistener.onPowerStateChanged(state);
        }
    }
} catch (Exception e) {
    //TODO: handle exception
    e.printStackTrace();
    Log.e(TAG, "onPowerStateChanged error!!!!  Exception: " + e.toString());
}
mPSListeners.finishBroadcast();
Android中,AIDLAndroid Interface Definition Language)是一种用于进程间通信的接口定义语言。当客户端与服务端跨进程通信时,AIDL可以用来定义服务接口和传输数据类型。对于回调列表,我们可以通过AIDL将客户端的回调接口传递给服务端,在服务端需要回调时,调用客户端的回调接口。 具体实现步骤如下: 1. 首先,在AIDL文件中定义回调接口。例如: ``` // ICallbackInterface.aidl interface ICallbackInterface { void onCallback(int value); } ``` 2. 在服务端的AIDL接口中添加一个注册回调的方法和一个注销回调的方法。例如: ``` // IMyService.aidl interface IMyService { void registerCallback(in ICallbackInterface callback); void unregisterCallback(in ICallbackInterface callback); } ``` 3. 在服务端实现AIDL接口,并在需要回调时调用客户端的回调接口。例如: ``` // MyService.java public class MyService extends Service { private List<ICallbackInterface> mCallbacks = new ArrayList<>(); private void onValueChanged(int value) { for (ICallbackInterface callback : mCallbacks) { try { callback.onCallback(value); } catch (RemoteException e) { // 处理异常 } } } private final IMyService.Stub mBinder = new IMyService.Stub() { @Override public void registerCallback(ICallbackInterface callback) throws RemoteException { mCallbacks.add(callback); } @Override public void unregisterCallback(ICallbackInterface callback) throws RemoteException { mCallbacks.remove(callback); } }; } ``` 4. 在客户端实现回调接口,并在需要时注册回调。例如: ``` // MainActivity.java public class MainActivity extends AppCompatActivity { private IMyService mService; private ICallbackInterface mCallback = new ICallbackInterface.Stub() { @Override public void onCallback(int value) throws RemoteException { // 处理回调值 } }; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = IMyService.Stub.asInterface(service); try { mService.registerCallback(mCallback); } catch (RemoteException e) { // 处理异常 } } @Override public void onServiceDisconnected(ComponentName name) { mService = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定服务 Intent intent = new Intent(this, MyService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); // 注销回调 if (mService != null) { try { mService.unregisterCallback(mCallback); } catch (RemoteException e) { // 处理异常 } } // 解绑服务 unbindService(mConnection); } } ``` 以上就是使用AIDL实现回调列表的基本步骤。需要注意的是,在使用AIDL时,需要注意线程安全问题,以及处理可能出现的异常情况。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值