天天看点

Android Aidl的使用第二章客户端监听数据变化1.新增一个 aidl 接口2.服务端修改3.客户端修改

接上篇 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