在之前的文章中简单的介绍了跨进程通信的基础知识、跨进程通讯的集中方式以及简单的记录了Binder的基础知识,接下来讨论一下Android中常用的AIDL以及Messenger这两种多进程通信方式。

AIDL

AIDL全称Android Interface Definition Language,即Android接口定义语言,是Binder机制实现的Android IPC使用比较广泛的工具,使用AIDL进行进程间通讯需要定义client和Server,其中client和Server可以在同一个应用也可以在不同的应用。接下来将通过相关代码展示AIDL的基本实现逻辑。

首先新建两个app项目,分为定义为client端和Server端,

Server端

建立相关的aidl文件以及bean对象

在Server端main目录下建立aidl文件夹以及相关的.aidl文件,并copy到client端,如图所示:

android sharedpreference跨进程 android跨进程通信工具_android


这里主要定义了IVuiService.aidl以及UserInfo.aidl,这里需要注意命名规范,一般都是以“I”开头,其内容如下:

// IVuiService.aidl
package com.example.aidltestserver;

import com.example.aidltestserver.UserInfo;
import com.example.aidltestserver.IUserInfoUpdateCallback;
// Declare any non-default types here with import statements

interface IVuiService {

    String getUserName();

    boolean setUserInfo(in UserInfo info);

    UserInfo getUserInfo();

    boolean addUserInfoUpdateCallback(in IUserInfoUpdateCallback callback);
}
// IUserInfoUpdateCallback.aidl
package com.example.aidltestserver;
// Declare any non-default types here with import statements
parcelable UserInfo;

aidl文件编写完成之后,要进行makeproject,As会自动生成相关的.java文件,这样在service中才可以使用。
这里有以下几点需要注意的地方:

  1. AIDL支持的数据类型
  • 基本数据类型
  • String、CharSequence
  • List,HashMap,其内部元素也需要被AIDL支持
  • 实现Parcelable接口的对象
  • AIDL 类型的接口,非普通接口
  1. 方向标识
  • in 表示输入参数,即服务端可以修改该类型
  • out 表示输出参数,即客户端可以修改该类型,客户端不行
  • inout 表示客户端和服务端都可以修改该类型
  1. 传递序列化对象,如下:
    首先需要声明相关的bean对象,实现Parcelable接口
public class UserInfo implements Parcelable {
    private String name = "张三";

    @RequiresApi(api = Build.VERSION_CODES.Q)
    public UserInfo(Parcel in) {
        name = in.readString();
    }

    public UserInfo() {
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    public void readFromParcel(Parcel source) {
        name = source.readString();
    }
    public static final Creator<UserInfo> CREATOR = new Creator<UserInfo>() {
        @RequiresApi(api = Build.VERSION_CODES.Q)
        @Override
        public UserInfo createFromParcel(Parcel in) {
            return new UserInfo(in);
        }

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

之后声明新建UserInfo.aidl文件,内容如下:

// IUserInfoUpdateCallback.aidl
package com.example.aidltestserver;
// Declare any non-default types here with import statements
parcelable UserInfo;

注意这里的parcelable是小写p开头,同时bean对象需要拷贝到client端。
5. 在AIDL文件中,除了基本数据类型、String、charsequence、list、map,其他在文件中使用的类,必须使用import语句导入相关的package,否则会报错。

新建service类,实现接口,处理客户端请求并将Binder返回
public class ServerService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

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

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new ServerBinder();
    }

    class ServerBinder extends IVuiService.Stub{
        @Override
        public String getUserName() throws RemoteException {
            return "测试";
        }

        @Override
        public boolean setUserInfo(com.example.aidltestserver.UserInfo info) throws RemoteException {
            return false;
        }


        @Override
        public com.example.aidltestserver.UserInfo getUserInfo() throws RemoteException {
            UserInfo userInfo = new UserInfo();
            userInfo.setName("李四");
            return userInfo;
        }

        @Override
        public boolean addUserInfoUpdateCallback(IUserInfoUpdateCallback callback) throws RemoteException {
            return false;
        }

    }
}
将service暴露出去
<service android:name=".service.ServerService">
             <intent-filter>
                 <action android:name="com.example.aidltestserver.service.ServerService"/>
             </intent-filter>
        </service>

以上是Server端的基本的代码了

client端逻辑

copy aidl文件以及bean文件

android sharedpreference跨进程 android跨进程通信工具_ide_02

启动service
private void startConnectService() {
        Intent intent = new Intent(ACTION_SERVICE);
        intent.setPackage(ACTION_SERVICE_PACKAGE);
        bindService(intent,connection, Context.BIND_AUTO_CREATE);
    }
服务连接之后通信
private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG, "onServiceConnected: "+name);
            if (service != null){
                iVuiService = IVuiService.Stub.asInterface(service);
                try {
                    String userName = iVuiService.getUserName();
                    Log.e(TAG, "onServiceConnected: username"+userName );
                    UserInfo userInfo = iVuiService.getUserInfo();
                    Log.e(TAG, "onServiceConnected: username.getName"+userInfo.getName() );
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "onServiceDisconnected: " );
        }
    };

AIDL重连

AIDL断开重连,实际上就是对service的重新绑定,所以监听到服务断开的时候进行重新绑定。

  1. 在bindService的时候,会有个服务连接状态监听,可以通过这个监听去监听断开的状态,然后进行重新绑定:
@Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "onServiceDisconnected: " );
            //重新绑定
        }
  1. Binder死亡代理
    死亡代理要在service连接成功和断开的时候分别注册/解注册
private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG, "onServiceConnected: "+name);
            if (service != null){
                try {
                    //设置死亡代理
                    service.linkToDeath(deathRecipient,0);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                iVuiService = IVuiService.Stub.asInterface(service);
                try {
                    String userName = iVuiService.getUserName();
                    Log.e(TAG, "onServiceConnected: username"+userName );
                    UserInfo userInfo = iVuiService.getUserInfo();
                    Log.e(TAG, "onServiceConnected: username.getName"+userInfo.getName() );
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "onServiceDisconnected: " );
            //重新绑定
        }
    };

    private IBinder.DeathRecipient deathRecipient=new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            //解绑
            if(iVuiService != null){
                iVuiService.asBinder().unlinkToDeath(deathRecipient,0);
                iVuiService = null;
            }
            //断开重新绑定
        }
    };