使用RemoteCallbackList操作aidl远程ipc调用

363 阅读3分钟

一、为什么使用RemoteCallbackList?

在使用aidl进行ipc的进程通信过程中,需要实时监听通信的信息和数据变化等,可以将callback保存到该RemoteCallbackList列表中,在需要使用的时候,进行调用。同时也可以防止重复调用同一个callback任务。

1、比较重要的几个方法

public class RemoteCallbackList<E extends IInterface> {
    // 初始化方法
    public RemoteCallbackList() {
        throw new RuntimeException("Stub!");
    }
    
    // 用于将callback监听注册到列表中,以供后续调用
    public boolean register(E callback) {
        throw new RuntimeException("Stub!");
    }

    public boolean register(E callback, Object cookie) {
        throw new RuntimeException("Stub!");
    }
    
    // 取消注册callback
    public boolean unregister(E callback) {
        throw new RuntimeException("Stub!");
    }

    // 开始对callback列表进行调用,返回值是回调集合的数量大小
    public int beginBroadcast() {
        throw new RuntimeException("Stub!");
    }

    // 获取index位置的callback
    public E getBroadcastItem(int index) {
        throw new RuntimeException("Stub!");
    }
    
    // 结束对callback列表的调用,并清除beginBroadcast的状态
    public void finishBroadcast() {
        throw new RuntimeException("Stub!");
    }
    
    /**
     * 与beginBroadcast返回值不一定相同,如果初始化时调用,返回值一样
     * 如果在使用过后或unregister/register,index不为0时调用,则返回值不同
     */
    // 获取当前callback列表的需要处理的数量
    public int getRegisteredCallbackCount() {
        throw new RuntimeException("Stub!");
    }

}

二、使用

1、服务端

i、编写aidl接口

// ICallbackTestCallback.aidl
package com.icallback;

oneway interface ICallbackTestCallback {

    void onReceived(String msg);

}
package com.icallback;

// import callback
import com.icallback.ICallbackTestCallback;

oneway interface ICallbackTestInterface {

    void registerListener(ICallbackTestCallback callback);

    void unregisterListener(ICallbackTestCallback callback);

    void sendMsg(String msg);
}

ii、调用service,开启服务

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

    private final RemoteCallbackList<ICallbackTestCallback> listenerList = new RemoteCallbackList<>();

    private boolean isConnected = false;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind()");
        return mBinder;
    }

    @Override
    public void onCreate() {
        Log.i(TAG, "OnCreate()");
        isConnected = true;
        new Thread(runnable).start();
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "OnStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.i(TAG, "OnDestroy()");
        isConnected = false;
        super.onDestroy();
    }

    /**
     * 实现Binder方法
     */
    private final ICallbackTestInterface.Stub mBinder = new ICallbackTestInterface.Stub() {

        @Override
        public void registerListener(ICallbackTestCallback callback) throws RemoteException {
            Log.i(TAG, "registerListener(), from pid = " + Binder.getCallingPid());
            listenerList.register(callback);
        }

        @Override
        public void unregisterListener(ICallbackTestCallback callback) throws RemoteException {
            Log.i(TAG, "unregisterListener(), from pid = " + Binder.getCallingPid());
            listenerList.unregister(callback);
        }

        @Override
        public void sendMsg(String msg) throws RemoteException {
            Log.i(TAG, "received msg: " + msg + ", from client pid = " + Binder.getCallingPid());
        }
    };

    /**
     * 发送信息给客户端
     * @param msg:信息
     */
    private void sendMsgToClients(String msg) {
        listenerList.beginBroadcast();
        for (int i = 0; i < listenerList.getRegisteredCallbackCount(); i++) {
            try {
                listenerList.getBroadcastItem(i).onReceived(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        listenerList.finishBroadcast();
    }

    /**
     * 发送信息给客户端的具体方法
     */
    private final Runnable runnable = () -> {
      int count = 0;
        while (isConnected) {
            try {
                Thread.sleep(500);
                sendMsgToClients(Integer.toString(count++));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
}

2、客户端

i、编写aidl接口

// ICallbackTestCallback.aidl
package com.zx.icallback;

interface ICallbackTestCallback {

    void onReceived(String msg);

}
package com.zx.icallback;

import com.zx.icallback.ICallbackTestCallback;

interface ICallbackTestInterface {

    void registerListener(ICallbackTestCallback callback);

    void unregisterListener(ICallbackTestCallback callback);

    void sendMsg(String msg);
}

ii、调用aidl

package com.binderclient;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.zx.icallback.ICallbackTestCallback;
import com.zx.icallback.ICallbackTestInterface;


public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private boolean isBind = false;

    ICallbackTestInterface remoteServer = null;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        findViewById(R.id.register_btn).setOnClickListener(view -> registerCallback());
        findViewById(R.id.unregister_btn).setOnClickListener(view -> unregisterCallback());
        findViewById(R.id.bind_btn).setOnClickListener(view -> bindServer());
    }

    @Override
    protected void onPause() {
        if (isBind) {
            registerCallback();
        }
        super.onPause();
    }

    @Override
    protected void onResume() {
        if (isBind) {
            registerCallback();
        }
        super.onResume();
    }

    private final ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.i(TAG, "onServiceConnected()");
            remoteServer = ICallbackTestInterface.Stub.asInterface(iBinder);
            registerCallback();
            isBind = true;
            try {
                iBinder.linkToDeath(() -> {
                    Log.i(TAG, "binder death");
                },0);
            } catch (RemoteException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.i(TAG, "onServiceDisconnected()");
        }
    };

    private final ICallbackTestCallback callback = new ICallbackTestCallback.Stub(){

        @Override
        public void onReceived(String msg) {
            Log.d(TAG, "received msg : " + msg + ", from server pid = " + Binder.getCallingPid());
        }
    };


    private void registerCallback(){
        if (remoteServer != null) {
            try {
                remoteServer.registerListener(callback);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }else {
            Log.e(TAG, "remoteServer is null!");
        }
    }

    private void unregisterCallback(){
        if (remoteServer != null) {
            try {
                remoteServer.unregisterListener(callback);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }else {
            Log.e(TAG, "remoteServer is null!");
        }
    }

    private void sendMsg(String msg) {
        if (remoteServer != null) {
            try {
                remoteServer.sendMsg(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }else {
            Log.e(TAG, "remoteServer is null!");
        }
    }

    private void bindServer(){
        Log.i(TAG, "bindServer");
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.icallback.server", "com.icallback.server.CallbackService"));
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }

}