简述
在android关于binder的简单通信过程的基础上添加关于RemoteCallbackList的使用,client端对server端进行register与unregister的过程,然后server主动给client端回调处理。
aidl文件修改
1.在IOnTestDataListener.aidl文件中加入register与unregister的方法
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主动触发远程回调的方法
// 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是新增的方法
服务端
主要实现代码如下所示
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端传递数据。
客户端
主要实现代码如下所示
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所示,
注册是调用如下实现
binder.registerCallback(callback1);
binder.registerCallback(callback2);
点击注册的按钮时,日志打印如下所示,日志来源于服务端输出信息
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的远程回调的具体实现
binder.sendData()
调用发送按钮时,client端的日志打印如下所示,从日志中可以看出客户端注册的回调中的callback1与callback2的onDealRegisterCbData方法被分别调用了。
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.反注册
反注册时调用如下实现
binder.unRegisterCallback(callback2);
binder.unRegisterCallback(callback1);
此时调用unRegister的按钮时,服务端的打印如下所示
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