Android通过Binder实现进程间通信

1、进程间通信

在Android应用开发里面,一般的APP都使用不到多进程开发,但一般来说,我们也接触过多进程相关的东西,比如说我们使用第三方推送的时候,这里的推送服务都是属于远程服务,APP并没有启动的时候,也会得到推送的消息。

进程间通信,也是比较模糊的概念,一直以来也不好理解,为什么进程间通信还要搞得那么复杂,当然这还得源于Android系统的安全性来考虑。

2、进程间通信的方式

进程间通信的方式比较多,Bundle、ContentProvider、AIDL、Messanger、共享文件、Socket等等。

AIDL是官方支持的,多进程、多线程,支持并发的进程间通信方式。也是本次要记录的IPC方式。另外,Messanger只支持单线程的进程间通信(内部也是通过AIDL实现)。

3、AIDL相关的知识点

通常说的进程间通信主要是指:Activity与远程服务Service的数据交互。那么这里涉及到几个知识点

1、Activity,如何绑定Service,在绑定的过程中如何拿到AIDL接口实现接口调用。

2、Service,AIDL接口的实现,在绑定成功之后,返回Binder引用到客户端。

3、Binder,进程间通信的桥梁,不同进程之间通信的提供协议。

4、AIDL,接口描述语言,描述接口,跟Java接口不同,不能定义变量,只可以定义方法。

5、传递对象,AIDL接口传参只允许传递基本数据类型,传递对象需要通过实现Parcelable接口。

6、Parcelable,对象想要实现进程间通信,就要实现Parcelable接口,才可以序列化后进行传递。

4、客户端如何发送消息给服务器端

4.1、定义AIDL接口

package com.example.aidl;
import com.example.aidl.data.CustomData;
import com.example.aidl.CustomReceiver;

interface CustomSender {
    void sendMessage(in CustomData customData);

    void register(CustomReceiver receiver);
    void unRegister(CustomReceiver receiver);
}

4.2、Activity首先绑定服务Service

private void startBindService() {
    Intent intent = new Intent(this, CustomService.class);
    bindService(intent, connection, Context.BIND_AUTO_CREATE);
}

4.3、在Service服务返回IBinder,Binder sender也需要在服务器端实现

@Override
public IBinder onBind(Intent intent) {
    return sender;
}

private IBinder sender = new CustomSender.Stub() {
    @Override
    public void sendMessage(CustomData customData) throws RemoteException {
        if (customData == null) {
            Log.i(TAG, "消息是空的");
        } else {
            String name = customData.getName();
            int id = customData.getId();
            Log.i(TAG, "收到客户端的消息:" + name + " " + id);
        }
    }
};

4.4、Activity绑定Service成功之后,通过返回来的IBinder,转换成为接口,从而实现了接口的调用

private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        CustomData data = new CustomData();
        data.setName("我的消息");
        data.setId(6);

        try {
            customSender = CustomSender.Stub.asInterface(service);
            customSender.sendMessage(data);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};

5、服务的如何推送消息至客户端

5.1、Activity实现消息接收器的AIDL接口

//消息监听回调接口
private CustomReceiver customReceiver = new CustomReceiver.Stub() {

    @Override
    public void onMessageReceived(String message) throws RemoteException {
        Log.i(TAG, "onMessageReceived: " + message);
    }
};

5.2、在服务器连接成功的时候,需要注册,有点像是观察者模式。

customSender.register(customReceiver);

5.3、服务端实现的接口方法

/**
 * 用于处理消息监听的类
 **/
private RemoteCallbackList listenerList = new RemoteCallbackList<>();

private IBinder sender = new CustomSender.Stub() {
    @Override
    public void register(CustomReceiver receiver) throws RemoteException {
        if (receiver != null) {
            listenerList.register(receiver);
        }
    }

    @Override
    public void unRegister(CustomReceiver receiver) throws RemoteException {
        if (receiver != null) {
            listenerList.unregister(receiver);
        }
    }
};

5.4、通常服务端会有一个线程与后台发生长连接,获取到数据之后,要通过遍历消息监听器列表,从而实现来此客户端的AIDL接口调用,这里模拟每3秒给客户端发送消息

private class MessageRunnable implements Runnable {
    @Override
    public void run() {
        while (!isDestroy.get()) {
            Log.i(TAG, "线程启动!");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            try {
                int size = listenerList.beginBroadcast();
                for (int i = 0; i < size; i++) {
                    CustomReceiver customReceiver = listenerList.getBroadcastItem(i);
                    if (customReceiver != null) {
                        customReceiver.onMessageReceive("来自服务器端的消息。时间:" + System.currentTimeMillis());
                    }
                }
                listenerList.finishBroadcast();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
}

6、重连机制 DeathRecipient

6.1、实现DeathRecipient,监测服务死亡的情况,比如服务Service挂掉了,这个时候应该重启服务

private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
    @Override
    public void binderDied() {
        if (customSender != null) {
            customSender.asBinder().unlinkToDeath(this, 0);
            customSender = null;
        }
        startBindService();
    }
};

6.2、在连接上的时候添加上

customSender.asBinder().linkToDeath(deathRecipient, 0);

7、如何做进程校验(初始化application,进程id,权限)

多进程会出现实现多个Application的情况,通常,我们Application里面的初始化却并不需要多次初始化,所以在Application的初始化onCreate()方法里面可以进行分进程而初始化,而区别进程的方法可以根据进程名称来实现。然后判断名称来实现相关的初始化。

private String getProcessName() {
    ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    List list = activityManager.getRunningAppProcesses();
    if (list == null) {
        return null;
    }

    for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : list) {
        if (runningAppProcessInfo != null && runningAppProcessInfo.pid == Process.myPid()) {
            return runningAppProcessInfo.processName;
        }
    }
    return null;
}

8、总结

进程间通信用的得当会变得相当强大,比如多个进程获得系统分配的内存也更大,可以实现的事件也更多,可以做的事情也是非常值得思考的,但使用不当,就只会给自己增加工作量,人还是要往前进步的,多一份知识多一条路。

你可能感兴趣的:(Android通过Binder实现进程间通信)