接上篇 Android Aidl的使用_南国樗里疾的博客-CSDN博客
https://blog.csdn.net/weixin_44021334/article/details/114920869 ,
目前可以在客户端获取数据和添加数据,怎么监听数据的变动呢?
如服务端数据有更新,客户端怎么及时知道呢,来探索下。
流程为:
- 1.新增一个 aidl 接口;
- 2.服务端修改;
- 3.客户端注册监听。
1.新增一个 aidl 接口
首先,在 aidl 文件夹下新建一个 aidl 文件 IOnNewCarAddListener.aidl ,
package com.test.relearnaidl.aidl;
import com.test.relearnaidl.aidl.Car;
interface IOnNewCarAddListener{
void onNewCarAdd(in Car newCar);
}
然后修改 ICarManager.aidl ,添加两个方法
// ICarManager.aidl
package com.test.relearnaidl.aidl;
import com.test.relearnaidl.aidl.Car;
import com.test.relearnaidl.aidl.IOnNewCarAddListener;
// Declare any non-default types here with import statements
interface ICarManager {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
List<Car> getCarList();
void addNewCar(in Car car);
void registerListener(IOnNewCarAddListener listener);
void unregisterListener(IOnNewCarAddListener listener);
}
2.服务端修改
修改的不多,主要是为了适配新加的接口。
- mBinder 对象实现新增的接口;
- 新增一个列表 mListenerList 存储注册的监听器,数据变化时通知到 mListenerList 里所有的 listenerList ;
- 添加一个 addRunnable 模拟数据变化。
package com.test.relearnaidl.service;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import androidx.annotation.Nullable;
import com.test.relearnaidl.aidl.Car;
import com.test.relearnaidl.aidl.ICarManager;
import com.test.relearnaidl.aidl.IOnNewCarAddListener;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class CarManagerService extends Service {
private CopyOnWriteArrayList<Car> mCarList = new CopyOnWriteArrayList<Car>();
private CopyOnWriteArrayList<IOnNewCarAddListener> mListenerList = new CopyOnWriteArrayList<IOnNewCarAddListener>();
private Binder mBinder = new ICarManager.Stub() {
@Override
public List<Car> getCarList() throws RemoteException {
return mCarList;
}
@Override
public void addNewCar(Car car) throws RemoteException {
mCarList.add(car);
onNewCarAdd(car);
}
@Override
public void registerListener(IOnNewCarAddListener listener) throws RemoteException {
if (!mListenerList.contains(listener)) {
mListenerList.add(listener);
} else {
Log.d("luoah", "[CarManagerService] -- registerListener -- this listener already exist");
}
}
@Override
public void unregisterListener(IOnNewCarAddListener listener) throws RemoteException {
if (mListenerList.contains(listener)) {
mListenerList.remove(listener);
} else {
Log.d("luoah", "[CarManagerService] -- unregisterListener -- listener not found");
}
}
};
private void onNewCarAdd(Car car) throws RemoteException{
mCarList.add(car);
for (int j = 0; j < mListenerList.size(); j++){
IOnNewCarAddListener listener = mListenerList.get(j);
listener.onNewCarAdd(car);
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
mCarList.add(new Car(100, "SUV_100"));
new Thread(new addRunnable()).start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
private class addRunnable implements Runnable{
@Override
public void run() {
try{
Thread.sleep(3000);
} catch (InterruptedException ie){
ie.printStackTrace();
}
try {
Car bcar = new Car(700, "BM_700");
onNewCarAdd(bcar);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
3.客户端修改
成功连接后注册 IOnNewCarAddListener ,退出时反注册。和广播很像。
package com.test.relearnaidl;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
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 android.widget.Button;
import com.test.relearnaidl.aidl.Car;
import com.test.relearnaidl.aidl.ICarManager;
import com.test.relearnaidl.aidl.IOnNewCarAddListener;
import com.test.relearnaidl.service.CarManagerService;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button mButtonBind, mButtonGet, mButtonAdd;
private ICarManager carManager;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
carManager = ICarManager.Stub.asInterface(service);
try {
List<Car> conCar = carManager.getCarList();
if (conCar != null && conCar.size() > 0) {
Log.d("luoah", "[MainActivity] -- onServiceConnected -- conCar:" + conCar.toString());
}
carManager.registerListener(clientListener);
} catch (RemoteException rme) {
rme.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
try {
carManager.unregisterListener(clientListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
private IOnNewCarAddListener clientListener = new IOnNewCarAddListener.Stub() {
@Override
public void onNewCarAdd(Car newCar) throws RemoteException {
Log.d("luoah", "[MainActivity] -- onNewCarAdd -- newCar:" + newCar.toString());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonBind = (Button)findViewById(R.id.button_bind);
mButtonGet = (Button)findViewById(R.id.button_get);
mButtonAdd = (Button)findViewById(R.id.button_add);
mButtonBind.setOnClickListener(this);
mButtonGet.setOnClickListener(this);
mButtonAdd.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_bind:
Intent intent = new Intent(MainActivity.this, CarManagerService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
break;
case R.id.button_get:
try {
List<Car> cars = carManager.getCarList();
if (cars != null && cars.size() > 0) {
Log.d("luoah", "[MainActivity] -- onClickGet -- cars:" + cars.toString());
}
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.button_add:
try {
carManager.addNewCar(new Car(200, "SUV_200"));
carManager.addNewCar(new Car(300, "SUV_300"));
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (carManager != null
&& carManager.asBinder().isBinderAlive()) {
try {
carManager.unregisterListener(clientListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(mConnection);
}
}
这样,当数据变化时,客户端就可以收到消息了。
But ,按返回键退出应用,log 是,
com.test.relearnaidl D/luoah: [CarManagerService] -- unregisterListener -- listener not found
纳尼,不是同一个 listener 吗,怎么找不到 ?
原因如下,摘抄自 《Android开发艺术探索》,
多进程无法奏效,因为 Binder 会把客户端传过来的对象重新转化成一个新的对象。虽然注册和解注册过程中使用的是同一个客户端对象,但是通过 Binder 传递到服务端后,却会产生两个全新的对象。别忘了对象是不能跨进程传递的,对象的跨进程传递本质上是反序列化的过程,这就是为什么 AIDL 中的自定义对象都必须要实现 Parcelable 接口。
解决这个问题,用
RemoteCallbackList
。