AIDL之双向通信

上一篇《Android进程通信一之AIDL》
说到进程A---->B拿去数据,那问题来了,B进程如果有了数据更新,如何回调给A啊?
这篇文章就来聊聊这个

原理

声明一个 AIDL 接口,然后在服务端所实现的 AIDL 接口中通过注册和注销来添加和删除声明的 AIDL 接口。然后在服务端需要发消息给客户端的时候遍历所有已注册的接口来发起通信,这就是为什么说AIDL可以一对多通信。

第一步

声明AIDL文件,并新增接口方法
AIDL之双向通信_第1张图片

// IMyAidlInterface.aidl
package com.ly.aidltest;
import com.ly.aidltest.Student;
import com.ly.aidltest.IReceive;

// Declare any non-default types here with import statements
/**除了默认的基本类型,就是下面直接生成出来的方法自带的这6种类型不需要import之外,其他的都需要手动import
* 其他类型包括下面几种:
*List 接口(会自动将List接口转为 ArrayList),且集合的每个元素都必须要么是基本类型,要么是Parcelable实现类
*Map 接口(会自动将 Map 接口转为 HashMap),且每个元素的 key 和 value 要么是基本类型,要么是Parcelable实现类
*Parcelable 的实现类
*AIDL 接口本身
*/


interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
    //定义两个方法,也就是提供给客户端的服务
    List<Student> getStudent();
    //这里的in 是有讲究的
    void addStudent(in Student stu);

    void registerListener(IReceive listener);
    void unregisterListener(IReceive listener);
}
第二步

服务端注册回调,并发送数据

public class MyService extends Service {
    private List<Student> list = new ArrayList<>();
     aidl 接口专用容器
    private RemoteCallbackList<IReceive>callbackList = new RemoteCallbackList<>();
    private static final String TAG = "MyService";
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate: ");
        list.add(new Student("小明", 12));
        list.add(new Student("小红", 13));
        list.add(new Student("小军", 14));
    }
    private IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }
        @Override
        public List<Student> getStudent() throws RemoteException {

            return list;
        }
        @Override
        public void addStudent(Student stu) throws RemoteException {
            Log.e(TAG, "setStudent: " );
            list.add(stu);
            //beginBroadcast----finishBroadcast成对出现
            int size = callbackList.beginBroadcast();
            // 向客户端通信
            for(int i=0;i<size;i++){
                IReceive receiver = (IReceive) callbackList.getBroadcastItem(i);
                receiver.onNewStudentAdded(stu);
            }
            callbackList.finishBroadcast();

        }

        @Override
        public void registerListener(IReceive listener) throws RemoteException {
            callbackList.register(listener);
        }

        @Override
        public void unregisterListener(IReceive listener) throws RemoteException {
            callbackList.unregister(listener);
        }
    };
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: " );
        return mBinder;
    }

第三步

客户端注册回调接收数据

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private  IMyAidlInterface sub;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            sub =  IMyAidlInterface.Stub.asInterface(service);
            try {
                List<Student> list = sub.getStudent();
                for(Student s : list){
                    Log.e(TAG, "onServiceConnected: "+s.getName()+" age:"+s.getAge());
                }
                sub.registerListener(listener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.tv).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(sub!=null){
                    try {
                        sub.addStudent(new Student("新来的",20));
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        Intent intent = new Intent();
        //5.0之后如果使用隐式启动service需要加上package
        intent.setPackage(getPackageName());
        intent.setAction("com.ly.aidltest.MyService");
        bindService(intent,connection,BIND_AUTO_CREATE);
    }

    private IReceive.Stub listener = new IReceive.Stub() {
        @Override
        public void onNewStudentAdded(Student stu) throws RemoteException {
            Log.e(TAG, "onNewStudentAdded--threadId"+Thread.currentThread().getId()+" name:"+stu.getName() );

        }
    };
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(sub!=null){
            try {
                sub.unregisterListener(listener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        unbindService(connection);
    }
}
RemoteCallbackList

这个对象只是Android帮我们封装的用于binder传输的对象而已,没有必要深究,实际上我们更要做的是不使用AIDL实现binder跨进程,这样才能真正理解Android的跨进程通信。
源码参见:
https://github.com/YuxiangZhu/AIDLTest

下一篇,我们来聊一聊binder原理,这样我们才知道AIDL到底省了我们多少事儿!

你可能感兴趣的:(Android中级)