android之binder关于RemoteCallbackList的使用

文章目录

简述

android关于binder的简单通信过程的基础上添加关于RemoteCallbackList的使用,client端对server端进行register与unregister的过程,然后server主动给client端回调处理。

aidl文件修改

1.在IOnTestDataListener.aidl文件中加入register与unregister的方法

java 复制代码
package com.example.test;
import com.example.test.IOnTestDataCallback;
// Declare any non-default types here with import statements

interface IOnTestDataListener {
    void registerCallback(in IOnTestDataCallback callback);
    oneway void sendData(String str, in byte[] bytes,in IOnTestDataCallback callback);
    void unRegisterCallback(in IOnTestDataCallback callback);
}

其中registerCallback与unRegisterCallback是新增的方法。

2.在IOnTestDataCallback.aidl中加入server主动触发远程回调的方法

java 复制代码
// IOnTestDataCallback.aidl
package com.example.test;
import com.example.test.TestDataBean;

// Declare any non-default types here with import statements

interface IOnTestDataCallback {
    void onCallback(in TestDataBean dataBean);
    void onDealRegisterCbData(String name,int number);
}

其中onDealRegisterCbData是新增的方法

服务端

主要实现代码如下所示

java 复制代码
package com.tencent.wemeet.testwhitelist;

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

import androidx.annotation.Nullable;

import com.example.test.IOnTestDataCallback;
import com.example.test.IOnTestDataListener;
import com.example.test.TestDataBean;

import java.util.Arrays;

public class TestBinderService extends Service {

    private static final String TAG = "TestBinderService";
    private final RemoteCallbackList<IOnTestDataCallback> remoteCallbackList = new RemoteCallbackList<>();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new IOnTestDataListener.Stub() {
            @Override
            public void registerCallback(IOnTestDataCallback callback) throws RemoteException {
                boolean register = remoteCallbackList.register(callback);
                Log.d(TAG, "register:" + register + ",remoteCallbackList :" + remoteCallbackList);
            }

            @Override
            public void sendData(String str, byte[] bytes, IOnTestDataCallback callback) throws RemoteException {
                Log.d(TAG, "str = " + str + ",bytes = " + Arrays.toString(bytes));
                TestDataBean bean = new TestDataBean();
                bean.setName("zhangsan");
                bean.setNumber(20);
                try {
                    Thread.sleep(5000);
                    callback.onCallback(bean);
                    // callback register data
                    int num = remoteCallbackList.beginBroadcast();
                    for (int i = 0; i < num; i++) {
                        IOnTestDataCallback broadcastItem = remoteCallbackList.getBroadcastItem(i);
                        broadcastItem.onDealRegisterCbData("xiaoming", i);
                    }
                    remoteCallbackList.finishBroadcast();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void unRegisterCallback(IOnTestDataCallback callback) throws RemoteException {
                boolean unregister = remoteCallbackList.unregister(callback);
                Log.d(TAG, "unregister:" + unregister + ",remoteCallbackList :" + remoteCallbackList);
            }
        };
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
    }
}

从上代码可以看出多了registerCallback与unRegisterCallback的方法的实现,同时在sendData中模拟了server端给client端的回调实现方式。代码实现如截图中的红色框所示,其目的是给每个register的client端传递数据。

客户端

主要实现代码如下所示

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

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

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

public class TestBinderActivity extends AppCompatActivity {

    public static final String TAG = "TestBinderActivity";
    private boolean isBinder;
    private IOnTestDataListener binder;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_binder_test);
        // 实现一个带有回调的aidl通信  其中有parcel参数的传递

        Intent intent = new Intent();
        intent.setAction("com.binder.test.service");
        intent.setPackage("com.tencent.wemeet.testwhitelist");
        isBinder = bindService(intent, connection, Context.BIND_AUTO_CREATE);

        IOnTestDataCallback callback1 = new IOnTestDataCallback.Stub() {
            @Override
            public void onCallback(TestDataBean dataBean) throws RemoteException {

            }

            @Override
            public void onDealRegisterCbData(String name, int number) throws RemoteException {
                Log.d(TAG, "11111 name = " + name + ",number = " + number);
            }
        };


        IOnTestDataCallback callback2 = new IOnTestDataCallback.Stub() {
            @Override
            public void onCallback(TestDataBean dataBean) throws RemoteException {

            }

            @Override
            public void onDealRegisterCbData(String name, int number) throws RemoteException {
                Log.d(TAG, "22222 name = " + name + ",number = " + number);
            }
        };

        findViewById(R.id.btn_register).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (binder == null) {
                    return;
                }
                try {
                    binder.registerCallback(callback1);
                    binder.registerCallback(callback2);
                } catch (RemoteException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        findViewById(R.id.btn_unregister).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    binder.unRegisterCallback(callback2);
                    binder.unRegisterCallback(callback1);
                } catch (RemoteException e) {
                    throw new RuntimeException(e);
                }

            }
        });


        findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (binder == null) {
                    Log.d(TAG, "binder is null");
                    return;
                }
                Log.d(TAG, "begin");
                try {
                    binder.sendData("123", new byte[]{1, 2, 3}, new IOnTestDataCallback.Stub() {
                        @Override
                        public void onCallback(TestDataBean dataBean) throws RemoteException {
                            Log.d(TAG, "name = " + dataBean.getName() + ",number = " + dataBean.getNumber());
                        }

                        @Override
                        public void onDealRegisterCbData(String name, int number) throws RemoteException {
                            Log.d(TAG, "333333 name = " + name + ",number = " + number);
                        }
                    });
                } catch (RemoteException e) {
                    Log.d(TAG, "sendData RemoteException");
                    throw new RuntimeException(e);
                }

                Log.d(TAG, "end");
            }
        });


    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (isBinder) {
            isBinder = false;
            unbindService(connection);
            connection = null;
            binder = null;
        }
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected");
            binder = IOnTestDataListener.Stub.asInterface(service);

        }

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

主要调用流程

1.注册

此处我们注册两个IOnTestDataCallback对象,如上面的callback1、callback2所示,

注册是调用如下实现

java 复制代码
   binder.registerCallback(callback1);
   binder.registerCallback(callback2);

点击注册的按钮时,日志打印如下所示,日志来源于服务端输出信息

java 复制代码
2024-09-04 14:02:44.192  4794-4815  TestBinderService       com.tencent.wemeet.testwhitelist     D  register:true,remoteCallbackList :android.os.RemoteCallbackList@825eba6
2024-09-04 14:02:44.193  4794-4815  TestBinderService       com.tencent.wemeet.testwhitelist     D  register:true,remoteCallbackList :android.os.RemoteCallbackList@825eba6

2.发送调用

当进行验证时是调用sendData方法,因为服务端针对此方法内部处理了RemoteCallbackList的远程回调的具体实现

java 复制代码
binder.sendData()

调用发送按钮时,client端的日志打印如下所示,从日志中可以看出客户端注册的回调中的callback1与callback2的onDealRegisterCbData方法被分别调用了。

java 复制代码
2024-09-04 14:05:32.087  2900-2900  TestBinderActivity      com.example.test                     D  begin
2024-09-04 14:05:32.088  2900-2900  TestBinderActivity      com.example.test                     D  end
2024-09-04 14:05:37.092  2900-2956  TestBinderActivity      com.example.test                     D  name = zhangsan,number = 20
2024-09-04 14:05:37.096  2900-2956  TestBinderActivity      com.example.test                     D  11111 name = xiaoming,number = 0
2024-09-04 14:05:37.101  2900-2956  TestBinderActivity      com.example.test                     D  22222 name = xiaoming,number = 1

3.反注册

反注册时调用如下实现

java 复制代码
   binder.unRegisterCallback(callback2);
   binder.unRegisterCallback(callback1);

此时调用unRegister的按钮时,服务端的打印如下所示

java 复制代码
2024-09-04 14:10:26.456  4794-4815  TestBinderService       com.tencent.wemeet.testwhitelist     D  unregister:true,remoteCallbackList :android.os.RemoteCallbackList@825eba6
2024-09-04 14:10:26.458  4794-4815  TestBinderService       com.tencent.wemeet.testwhitelist     D  unregister:true,remoteCallbackList :android.os.RemoteCallbackList@825eba6
相关推荐
曙曙学编程3 分钟前
初级数据结构——树
android·java·数据结构
闲暇部落2 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX4 小时前
Android 分区相关介绍
android
大白要努力!5 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee5 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood5 小时前
Perfetto学习大全
android·性能优化·perfetto
Dnelic-8 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Eastsea.Chen11 小时前
MTK Android12 user版本MtkLogger
android·framework
长亭外的少年18 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
建群新人小猿20 小时前
会员等级经验问题
android·开发语言·前端·javascript·php