开发艺术之旅 | IPC机制


经常会听到AIDL、Binder机制,但是其实很多时候用不到(可能只是我用得少hhh),有时间来总结下吧,先看一些名词:

  • IPC(Inter—Process Communication) 跨进程通信
  • AIDL( Android Interface Definition Language),Android接口定义语言,是用于定义服务器和客户端通信接口的一种描述语言。
  • RPC (Remote Procedure Call) 远程调用

推荐参考:厘米姑娘的学习笔记

基础

使用多进程模式

  • Android使用多进程的方法只有一个:在AndroidManifest文件中给四大组件指定android:progress属性
  • 多进程会遇到的问题
  1. 静态成员和单例模式完全失效
  2. 线程同步机制失效
  3. SharePreferences 可靠性下降
  4. Application多次创建

序列化传输数据

  • Serializable 接口
  • Parcelable 接口

Serializable

  • 直接实现这个接口,系统自动实现,属于java1的接口,但是效率相对较低

Parcelable

  • 实现这个接口,实现这个接口后会需要我们实现几个方法,一般只要进行读取、写入这个两个方法就可以了
public class User implements Parcelable {

    public int userId;
    public String userName;
    public boolean isMale;

    public User(int userId, String userName, boolean isMale) {
        this.userId = userId;
        this.userName = userName;
        this.isMale = isMale;
    }

    // 快捷生成的构造函数,在这读取函数
    protected User(Parcel in) {

        userId = in.readInt();
        userName = in.readString();
        isMale = in.readInt() == 1;

    }

    // 自动生成 不必修改
    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    // 自动生成 除非存在 文件描述符 需要返回 1 否则不必修改
    @Override
    public int describeContents() {
        return 0;
    }

    // 需要实现这个方法,把参数写入
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(userId);
        dest.writeString(userName);
        dest.writeInt(isMale ? 1 : 0);
    }
}

Binder

几个角度简单理解

  • 是Android中的一个类,实现了IBinder接口
  • 是Android中一种跨进程通信方式
  • 从Android Framework来看,是ServiceManager连接各种Manager的桥梁
  • 从Android 应用层来看,是服务端和客户端进行通信的媒介(bindService会返回)

使用AIDL文件

在这里插入图片描述
新建两个文件

// User.aidl
package com.wj.aidltest;

parcelable User;

**********************************

// IUserManager.aidl
package com.wj.aidltest;

import com.wj.aidltest.User; // 需要手动import

interface IUserManager {

   List<User> getUserList();
   void addUser(in User user);

}

之后AS就会为我们生成IUserManager文件了,通过这个文件可以帮助我们理解Binder机制,这个生成的文件在

app\build\generated\aidl_source_output_dir\debug\compileDebugAidl\out\com\wj\aidltest\IUserManager.java

了解AIDL

AIDL文件其实是可以帮我们快速生成Binder代码的工具,常用到方法和需要了解的类:例如一个IUserManager.aidl文件,生成的相关类、方法

  • IUserManager:是一个继承 android.os.IInterface 的接口,包含我们定义的方法
  • Stub类:Binder对象实现类,服务端返回给客户端调用
  • Stub.Proxy:Binder对象的代理类,如果是跨进程调用会返回代理类
  • Stub.asBinder:返回Binder类本身
  • Stub.asInterface:客户端调用,将Binder类转换成客户端需要的AIDL接口
  • Stub.onTransact():当客户端发起跨进程请求时,经过层层封装最后会走到这个方法,运行在Binder线程池中
  • Stub.transact():IBinder接口方法,跨进程调用时Stub.Proxy会调用此方法,客户端线程挂起,知道服务端
    onTransact方法返回结果

IUserManager.java 结构

内部包含了我们定义的两个方法以及 一个继承Binder并且实现了这个接口的Stub抽象类,主要逻辑都在Stub这个类,Stub这个类又包含了一个Proxy类

public interface IUserManager extends android.os.IInterface{
   
  public static abstract class Stub extends android.os.Binder implements com.wj.aidltest.IUserManager{
   ... 
  }
  // 待实现
  public java.util.List<com.wj.aidltest.User> getUserList() throws android.os.RemoteException;
   // 待实现
  public void addUser(com.wj.aidltest.User user) throws android.os.RemoteException;

}

Stub类

Stub 类实现了IUserManager 接口,分析如下
分析以 getUserList 方法为例

 public static abstract class Stub extends android.os.Binder implements com.wj.aidltest.IUserManager{
     // 标识 为完整类名
    private static final java.lang.String DESCRIPTOR = "com.wj.aidltest.IUserManager";
    // 定义两个标识,用于判断是哪个方法
       static final int TRANSACTION_getUserList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    
    /** Construct the stub at attach it to the interface. */
    // 构造函数 连接到接口
    public Stub() {
      this.attachInterface(this, DESCRIPTOR);
    }

     // 将Binder对象转换成客户端所需要的AIDL接口类型对象,具体逻辑如下
     public static com.wj.aidltest.IUserManager asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      // 获取
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      // 如果是本地进程,返回本身
      if (((iin!=null)&&(iin instanceof com.wj.aidltest.IUserManager))) {
        return ((com.wj.aidltest.IUserManager)iin);
      }
      // 如果不是本地进程,返回Stub内部的一个代理类,具体见下面
      return new com.wj.aidltest.IUserManager.Stub.Proxy(obj);
    }
    
    // 获取Binder对象,返回本身 
    @Override public android.os.IBinder asBinder()
    {
      return this;
    }

    // 跨进程调用会走到这个方法
    // 1、 code 判断是那个方法
    // 2、 data 取出需要的参数
    // 3、 reply 存储方法返回结果 在proxy类会读取
    // return : 如果为false 客户端请求会失败
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_getUserList:
        {
          
          data.enforceInterface(descriptor);
          // 调用本地的getUserList方法
          java.util.List<com.wj.aidltest.User> _result = this.getUserList();
          reply.writeNoException();
          // 将结果写入,
          reply.writeTypedList(_result);
          return true;
        }
        case TRANSACTION_addUser:
        {
          data.enforceInterface(descriptor);
          com.wj.aidltest.User _arg0;
          if ((0!=data.readInt())) {
            _arg0 = com.wj.aidltest.User.CREATOR.createFromParcel(data);
          }
          else {
            _arg0 = null;
          }
          this.addUser(_arg0);
          reply.writeNoException();
          return true;
        }
        default:
        return super.onTransact(code, data, reply, flags);
      }
    }
    // onTransact end //

}

Stub.Proxy 类

远程进程调用会返回这个对象
分析以 getUserList 方法为例

private static class Proxy implements com.wj.aidltest.IUserManager
    {
      private android.os.IBinder mRemote;
      // 传入 IBinder对象
      Proxy(android.os.IBinder remote){
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder(){
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor(){
        return DESCRIPTOR;
      }
      // 跨进程调用方法:
      @Override public java.util.List<com.wj.aidltest.User> getUserList() throws android.os.RemoteException{
        // 创建data用于存储参数
        // 创建reply 传给Stub类,Stub的onTransact写入结果后再读出
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.util.List<com.wj.aidltest.User> _result;
        try {
          // 写入标识
          _data.writeInterfaceToken(DESCRIPTOR);
          // 调用Stub的transact方法,传入定义好的标识、参数、用于接收结果的Parcel
          boolean _status = mRemote.transact(Stub.TRANSACTION_getUserList, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getUserList();
          }
          _reply.readException();
          // 从reply读取结果
          _result = _reply.createTypedArrayList(com.wj.aidltest.User.CREATOR);
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        // 返回结果
        return _result;
      }
      @Override public void addUser(com.wj.aidltest.User user) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          if ((user!=null)) {
            _data.writeInt(1);
            user.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          boolean _status = mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().addUser(user);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      public static com.wj.aidltest.IUserManager sDefaultImpl;
    }

小结

Q:为什么跨进程需要使用AIDL等机制?

在 Stub的asInterface 方法,如果是本地进程,会返回一个Stub对象本身;
如果不是同一进程,就会返回一个Stub.Proxy 对象,进而导致我们在ServiceConnection的onServiceConnected接收到的IBinder对象其实是一个BinderProxy,而不是Binder,所以不能转换成我们自己定义的Binder,会报错,需要用到AIDL或者Messenger等跨进程机制

Q:Stub.Proxy 如何实现跨进程调用?

  • Stub.Proxy 实现了我们定义的接口,但是他的实现方法是,通过调用Stub的transact方法,传入需要的参数、一个用于接收返回值的Parcel以及方法标识,最后Stub回调到onTransact方法。
  • 在onTransact方法会取出参数,调用Stub相应的方法,再把结果写入传入的Parcel;
  • 在onTransact执行完方法后,在Stub.Proxy相应的方法会取出结果并返回

流程图
在这里插入图片描述

Android几种IPC机制

  • Bundle 启动另一个进程的Activity、Service、Receiver,可以在Bundle中富家我们需要传输给远程的信息
  • 使用文件共享,通过文件为媒介,传输信息(不推荐使用SharePreferences)
  • 使用Messenger
  • 使用AIDL
  • socket通信

重点是Messenger 和 AIDL

Messenger

底层也是基于AIDL ,可以简单的进行进程间通信,但是它一次只能处理一次请求,类似串行通信,所以不必考虑并发的问题,也不适合大量的并发请求

使用

在服务端

  1. 新建一个远程服务
  2. 新建一个Handler,用于处理从客户端发过来的消息
  3. 新建一个Messenger,把第二步构建的Handler传入
  4. 在onBind方法,返回Messenger.getBinder()
  5. 如果需要实现服务端向客户端发送消息,从 Message.replyTo 获取客户端的 Messenger,通过这个Messenger发送消息
public class MessengerService extends Service {

    // 2. 新建一个Messenger 构造函数传入下面构建的Handler
    private final Messenger mMessenger = new Messenger(new MessengerHandler());

    public MessengerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // 3. 返回mMessenger.getBinder 的Binder对象
        return mMessenger.getBinder();
    }

    // 1. 新建一个Handler处理信息
    private static class MessengerHandler extends Handler{

        private String TAG = "MessengerHandler";

        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what){
                case 1:
                    // 打印收到的信息
                    Log.d(TAG, "rec from client: "+ msg.getData().getString("data"));
                    // 获取客户端传过来的 Messenger 用于 给客户端发送消息
                    Messenger client = msg.replyTo;
                    Message replyMsg = Message.obtain();
                    replyMsg.what = 2;
                    Bundle data = new Bundle();
                    data.putString("reply","i have receive you msg");
                    replyMsg.setData(data);

                    try {
                        // 发送消息
                        client.send(replyMsg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }

                    break;
            }
        }
    }
}

客户端

  1. 新建一个ServiceConnection,在onServiceConnected中初始化一个Messenger 【Messenger mService = new Messenger(IBinder);
  2. 通过第一步创建的Messenger,就可以向服务端发送消息了
  3. 如果需要接收服务端发送过来的消息,需要新建一个客户端自己的Messenger,并传入一个客户端自己的Handler 处理服务端传过来的消息,并且在发送消息给 服务端时,在message的reply字段将这个Messenger赋值
    4.bindService 开始通信

具体如下

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    public String TAG = "MainActivity";

    // 通过服务端返回的IBinder构建的Messenger 用于给服务端发消息
    private Messenger mService;
    private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.main_tv);
        textView.setOnClickListener(v -> {
            // 一个简单的监听,绑定服务
            Intent intent = new Intent(this,MessengerService.class);
            bindService(intent,connection,BIND_AUTO_CREATE);
        });

    }
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
           // 通过返回的IBinder 构建给服务端发消息的Messenger
            mService = new android.os.Messenger(service);
            Message msg = Message.obtain();
            msg.what = 1;
            Bundle data = new Bundle();
            data.putString("data","Hello,this is msg from client");
            msg.setData(data);
            // 重点:实现双向通信,需要在这个字段将客户端定义的Messenger传过去
            msg.replyTo = mGetReplyMessenger;
            try {
                // 发送消息
                mService.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    // 用于处理服务端发送过来的消息,这里简单打印一下
    private static class MessengerHandler extends Handler{
        private String TAG = "MessengerHandler";

        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what){
                case 2:
                    Log.d(TAG, "handleMessage: " + msg.getData().getString("reply"));
                    break;
            }
        }
    }

}

结果实例

两个进程
在这里插入图片描述
客户端:
在这里插入图片描述
服务端:
在这里插入图片描述
进程ID是不一样的

流程图
在这里插入图片描述

AIDL

相对于Messenger,AIDL适合大量并发请求的情况,同时Messenger适用于服务端和客户端发送消息,并不能调用服务端的方法,如果需要调用服务端的方法(RPC),还是需要用到AIDL

注意点:

  • 服务端和客户端的自定义bean类和aidl文件需要在相同的包下
  • 服务端的Service必须是可以被外部调用的
  • 调用的线程会被挂起,如果服务端是耗时操作需要在子线程,否则会导致ANR
  • 调用的方法(服务端调用客户端或者客户端调用服务端)运行在Binder线程池,如果有相关的监听、回调也是在子线程(不能操作UI)
属性 默认值 含义
android:enabled boolean 默认为true 是否能被系统实例化
android:exported boolean 默认为true 是否能被其他应用组件调用
android:permission String 无 需要的权限,可以自定义
android:process String 无 指定进程名称
  • AIDL支持的数据类型
  1. 基本的数据类型
  2. String 和 CharSequence
  3. 只支持ArrayList,并且里面的元素要被AIDL支持
  4. 只支持HashMap,并且里面的元素要被AIDL支持
  5. Parcelable 所有实现了Parcelable 的对象
  6. AIDL 接口
  • 自定义的Parcelable 需要显示的import进来,并且新建一个同名的AIDL文件声明它为Parcelable

使用

服务端
  1. 创建AIDL接口
  2. 创建远程服务
  3. 实现接口
  • 创建AIDL接口
// IUserManager.aidl
import com.wj.aidlremote.User;

interface IUserManager {
   List<User> getUserList();
   void addUser(in User user);

}
// User.aidl
package com.wj.aidlremote;

parcelable User;
  • 创建远程服务
public class AIDLService extends Service {

    private CopyOnWriteArrayList<User> mUserList = new CopyOnWriteArrayList<>();
    private String TAG = "AIDLService";

    public AIDLService() {

    }

    @Override
    public void onCreate() {
        super.onCreate();

        mUserList.add(new User(1,"one",true));
        mUserList.add(new User(2,"two",false));

    }

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

    private Binder mBinder = new IUserManager.Stub() {
        @Override
        public List<User> getUserList() throws RemoteException {
            return mUserList;
        }

        @Override
        public void addUser(User user) throws RemoteException {
            mUserList.add(user);
            Log.d(TAG, "addUser,size : " + mUserList.size());
        }

        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            return super.onTransact(code, data, reply, flags);
        }
    };
}

// AndroidManifest
    <service
        android:name=".AIDLService"
        android:enabled="true"
        android:exported="true"
        android:process=":aidl.remote">
    </service>
客户端
        // 调用其他应用的服务,第一个为包名 第二个为类名全路径
        Intent intent = new Intent();
        intent.setComponent(new ComponentName(
                "com.wj.aidlremote",
                "com.wj.aidlremote.AIDLService"
        ));
        bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
        
        // ServiceConnection 
        private IUserManager iUserManager;
        private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 转化为接口实例
            iUserManager = IUserManager.Stub.asInterface(service);

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
设置死亡代理

在远程服务“挂”了的时候,可以进行重新连接

    // 在连接到服务时设置代理
    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iUserManager = IUserManager.Stub.asInterface(service);

            try {
                service.linkToDeath(mDeathRecipient,0);

            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
             // 也可以在这里重新连接服务,不同点在于 这个方法在客户端的UI线程,
             // binderDied在客户端的Binder线程池
        }
    };

    // 新建一个DeathRecipient 对象
    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            if (iUserManager == null) return;

            // 先解除监听
            iUserManager.asBinder().unlinkToDeath(mDeathRecipient,0);
            iUserManager = null;

            // 重新绑定服务
            Intent intent = new Intent();
            intent.setComponent(new ComponentName(
                    "com.wj.aidlremote",
                    "com.wj.aidlremote.AIDLService"
            ));
            bindService(intent,mServiceConnection,BIND_AUTO_CREATE);

        }
    };
设置、移除监听

如果想给服务设定一个监听,比如当服务端添加了一个新用户的时候,就回调到客户端,可以给服务端设定一个监听

// 1. 定义一个aidl接口
// IOnNewUserAddListener.aidl
package com.wj.aidlremote;

import com.wj.aidlremote.User;

interface IOnNewUserAddListener {
    void onNewUserAdded(in User user);
}

// 2. 修改原有的aidl接口
// IUserManager.aidl
import com.wj.aidlremote.User;
import com.wj.aidlremote.IOnNewUserAddListener;

interface IUserManager {

   List<User> getUserList();
   void addUser(in User user);

   void registerListListener(IOnNewUserAddListener listener);
   void unregisterListListener(IOnNewUserAddListener listener);

}
// 3. 修改Binder实现

// ** 注意 监听器需要用到 RemoteCallbackList 否则无法移除监听(传输后对象不同,无法找到对象)
private RemoteCallbackList<IOnNewUserAddListener> mListeners = new RemoteCallbackList<>();
    
private Binder mBinder = new IUserManager.Stub() {
        @Override
        public List<User> getUserList() throws RemoteException {
            return mUserList;
        }

        @Override
        public void addUser(User user) throws RemoteException {
            mUserList.add(user);
            Log.d(TAG, "addUser,size : " + mUserList.size());
            // 遍历必须通过以下方式:
            int N = mListeners.beginBroadcast();
            for (int i = 0;i < N;i++){
                IOnNewUserAddListener listener = mListeners.getBroadcastItem(i);
                if (listener != null){
                    listener.onNewUserAdded(user);
                }
            }
            // beginBroadcast 必须和finishBroadcast 成对使用
            mListeners.finishBroadcast();
        }

        // 注册监听
        @Override
        public void registerListListener(IOnNewUserAddListener listener) throws RemoteException {

            mListeners.register(listener);
        }

        // 解除注册
        @Override
        public void unregisterListListener(IOnNewUserAddListener listener) throws RemoteException {
            mListeners.unregister(listener);
        }


        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            return super.onTransact(code, data, reply, flags);
        }
    };

// 4. 在客户端设置监听
    private IOnNewUserAddListener.Stub iOnNewUserAddListener = new IOnNewUserAddListener.Stub() {
        @Override
        public void onNewUserAdded(User user) throws RemoteException {
             ...
             //进行操作 但是注意这里是Binde线程池的线程,如果需要操作UI可以搭配Handler使用
        }
    }; 

// 注册监听
iUserManager.registerListListener(iOnNewUserAddListener);
权限配置

服务端

  • 定义权限
  • 在 Binder的onTransact进行权限判断
      // Android Manifest
      <permission 
        android:name="com.hjl.aidl.AIDL_SERVICE_PERMISSION"
        android:protectionLevel="normal"/>


      // Binder onTransact 进行权限判断(AIDL远程调用时才会用到)
        ...
        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {

             // 权限判断
            int check = checkCallingPermission("com.hjl.aidl.AIDL_SERVICE_PERMISSION");
            if (check == PackageManager.PERMISSION_DENIED){
                return false;
            }

            // 包名校验
            String packageName = null;
            String[] packages = getPackageManager().getPackagesForUid(getCallingUid());
            if(packages != null && packages.length > 0){
                packageName = packages[0];
            }
            if(!packageName.startsWith("com.wj")){
                return false;
            }
            
            return super.onTransact(code, data, reply, flags);
        }
        ...

客户端

添加权限

    <uses-permission android:name="com.hjl.aidl.AIDL_SERVICE_PERMISSION"/>

Socket通信

注意事项:

  • 声明权限
  • 不能在主线程中访问网络
<uses-permission android:name="android.permission.INTERNET" />  
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  

Socket两种使用方式:TCP / UDP

  • 流套接字:基于TCP协议,采用流的方式提供可靠的字节流服务。
  • 数据报套接字:基于UDP协议,采用数据报文提供数据打包发送的服务。

图片来自上面的**推荐参考**
在这里插入图片描述
使用步骤

客户端:

  1. 创建Socket对象,传入服务端地址、端口
  2. 等到连接成功,可以发送/接收消息
  3. 断开连接,关闭Socket

服务端:

  1. 创建Socket实例,监听端口
  2. 监听到连接,创建Socket对象,并通过Socket对象进行 发送/接收
  3. 断开连接,关闭输入输出流、Socket
ServerSocket serverSocket = new ServerSocket(8688);

Binder连接池

在使用AIDL的时候,如果每一个业务接口都要启动一个远程服务,是非常耗费资源&低效的,所以有了Binder连接池这个概念
使用步骤

  • 创建多个AIDL业务接口,以及他们的实现类(客户端&服务端);创建IBinderPool AIDL接口
  • 创建BinderPool类(包装连接服务、死亡代理等)、IBinderPool的实现类BinderPoolImpl,在BinderPoolImpl实现根据code返回对应的Binder
  • 创建BinderPoolService,onBind返回BinderPoolImpl对象
  • 客户端:实例化BindPool对象,并通过这个对象查找到相应的Binder对象,再通过这个Binder转换成对应的接口,就可以调用相应的方法了

服务端&客户端 BinderPool 代码

public class BinderPool {

    private static final String TAG = "BinderPool";

    public static final int BINDER_CODE = 1;

    public static final int BINDER_ADD = 2; // 接口标志位

    public static final int BINDER_MINUS = 3; // 接口标志位

    private Context mContext;
    private IBinderPool mBinderPool; // IBinderPool 接口

    private static volatile BinderPool sInstance; // 单例模式 

    // 将异步转成同步
    private CountDownLatch mConnectBinderPoolCountDownLatch; 

    private BinderPool(Context context){
        mContext = context.getApplicationContext();
        connectBinderPoolService();
    }

    // 单例模式 
    public static BinderPool getInstance(Context context){

        if (sInstance == null){

            synchronized (BinderPool.class){
                if (sInstance == null){
                    sInstance = new BinderPool(context);
                }
            }
        }
        return sInstance;
    }
    
    
    private synchronized void connectBinderPoolService(){
        mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
        // 绑定远程服务
        Intent service = new Intent();
        service.setComponent(new ComponentName(
                "com.wj.aidlremote",
                "com.wj.aidlremote.BinderPoolService"
        ));
        mContext.bindService(service,mBinderPoolConnection,Context.BIND_AUTO_CREATE);
        try {
            // 线程挂起,等到连接时唤醒 
            mConnectBinderPoolCountDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
    
    private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 获取IBinderPool接口对象
            mBinderPool = IBinderPool.Stub.asInterface(service);
            try {
                
                // 设置死亡代理
                mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient,0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            mConnectBinderPoolCountDownLatch.countDown(); // 唤醒线程
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    /**
     * 包装IBinderPool 供外部调用
     * @param binderCode
     * @return
     */
    public IBinder queryBinder(int binderCode){

        IBinder binder = null;
        if (mBinderPool != null){
            try {
                binder = mBinderPool.queryBinder(binderCode);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        return binder;
    }

    // 为服务设置的死亡代理
    private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            Log.w(TAG, "binder Died");
            mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0);
            mBinderPool = null;
            connectBinderPoolService();

        }
    };

    
    // IBinderPool的实现类,根据binderCode返回对应的IBinder
    public static class BinderPoolImpl extends IBinderPool.Stub{

        IBinder binder = null;

        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {

            IBinder binder = null;


            switch (binderCode){
                case BINDER_ADD:
                    // IComputeImpl为ICompute的实现类
                    binder = new IComputeImpl();
                    break;
                case BINDER_MINUS:
                    // IMinusImpl为IMinus的实现类
                    binder = new IMinusImpl();
                case BINDER_CODE:
                    // binder = new ExampleImel();
                    break;
                default:
                    break;
            }

            return binder;
        }
    }

服务端 BinderPoolService

public class BinderPoolService extends Service {

    private static final String TAG = "BinderPoolService";

    private Binder mBinderPool = new BinderPool.BinderPoolImpl();

    public BinderPoolService() {

    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        return mBinderPool; // BinderPool.BinderPoolImpl()实例
    }
}

客户端

        ...
        // 子线程实例化、连接远程服务
        new Thread(){
            @Override
            public void run() {
                pool = BinderPool.getInstance(MainActivity.this);
            }
        }.start();
        // 根据code 获取业务接口,进行接口调用
        
         IBinder binder = pool.queryBinder(BinderPool.BINDER_ADD);
            ICompute iCompute = IComputeImpl.asInterface(binder);
            try {
                int res  = iCompute.add(1,1);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

推荐参考

IPC机制比较

名称 优点 缺点 适用场景
Bundle 简单易用 只能传输Bundle支持的数据类型 四大组件间的进程间通信
文件共享 简单易用 不适合高并发场景,并且无法做到进程间的即时通信 无并发访问情形,交换简单的数据实时性不高的场景
AIDL 功能强大,支持一对多并发通信,支持实时通信 使用稍复杂需要处理好线程同步 一对多通信且有RPC需求
Messenger 功能一般,支持一对多串行通信,支持实时通信 不能很好处理高并发情形不支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型 低并发的一对多即时通信,无RPC需求,或者无需返回结果的RPC需求
ContentProvider 在数据源访问方面功能强大,支持一对多并发数据共享,可通过Call方法扩展其他操作 可以理解为受约束的AIDL,主要提供数据源的CRUD操作 一对多的进程间的数据共享
Socket 功能强大,可以通过网络传输字节流,支持一对多并发实时通信 实现细节稍微有点繁琐,不支持直接的RPC 网络数据交换
发布了27 篇原创文章 · 获赞 6 · 访问量 1648

猜你喜欢

转载自blog.csdn.net/weixin_41802023/article/details/103330696
今日推荐