【Android】自定义Binder与进程间通信

   多进程需求在我们开发中常有遇见,因而学习多进程的通信机制是非常有必要的。我们知道,AIDL、Messenger等常用的进程间通信框架都是对Binder的封装,所以,学习Binder的使用对后续理解Binder机制有非常大的好处。本篇目的就是要从自定义Binder出发,实现基本的进程间通信功能。

   我们的例子从一个加法服务出发,首先我们创建一个Service,该Service实现对其他进程传递来的两个参数做加法运算,并将运算结果进行返回。

public class MyService extends Service {
    private static final String TAG = "MyService";

    @Override
    public IBinder onBind(Intent intent) {
        OLog.i(TAG, "onBind");
        return myBinder;
    }

    Binder myBinder = new Binder() {
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code) {
                case RemoteProtocal.CODE_ADD: {
                    int a = data.readInt();
                    int b = data.readInt();
                    int result = add(a, b);
                    reply.writeInt(result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
    };

    public int add(int a, int b) {
        return a + b;
    }
}
上面我们自定义了一个Binder,并重写了其onTransact方法,需要注意的是,onTransact有四个参数,其含义分别如下:

   code: 标识码,用于区分操作,该值由Client端传递过来。

   data: 是一个容器,用于包裹Client传递过来的参数数据

   reply: 是一个容器,用于包裹返回给Client端的结果数据

   flags: 表明是否有返回值,0表示有返回值,1表示没有返回值。该值在Server端无需做处理,而对于Client端来说需要进行指定。

这里Code自定义如下

public class RemoteProtocal {
    public static final int CODE_ADD = 1;
}

   onTransact方法中做了以下几步操作,首先判断code的取值是否是RemoteProtocal.CODE_ADD,是的话则说明Client端需要的是进行加法操作,进而下一步则是从data中获取由Client端传入的参数,这里实际上传进来的是两个int类型的数据,所以调用data的readInt方法分别获取到两个参数a,b,之后调用add方法求和,获取a+b的结果,并将结果写入到reply中,需要注意的是,方法最后还需要 return true。

   这里,为了让确保我们的Service是运行在其他进程的,我们还需要在Mainifest中声明他的进程名,只需修改process属性

<service
            android:name=".server.MyService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote" />

  以上是Service的全部实现,接下来我们需要在Client端来绑定Service。

   对于绑定一个Service,我们可以如下进行实现

    // 绑定远程服务
    private void bindRemoteService() {
        // 远程服务具体名称
        ComponentName componentName = new ComponentName(this, "com.me.obo.mybinder.server.MyService");
        Intent intent = new Intent();
        intent.setComponent(componentName);
        // 绑定到服务
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            // 持有binder的引用
            mBinder = iBinder;
            tvConnectState.setText("Connected");
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {}
    };
   这块代码先是绑定了上面的Service,之后获取到Service返回的一个Binder的引用,该引用其实就是由Service里面返回的那个自定义Binder在Client端的映射对象。也就是说,操作这个iBinder对象,相当于操作Service里面的myBinder对象,我们将iBinder存在本地为mBinder。接下来,我们开始操作这个mBinder来达到使用远程服务的目的。

我们实现以下的方法

/**
     * 加法运算
     * @param a
     * @param b
     */
    private int add(int a, int b) {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        // 写入参数 a
        data.writeInt(a);
        // 写入参数 b
        data.writeInt(b);
        try {
            // 调用远程服务
            mBinder.transact(RemoteProtocal.CODE_ADD, data, reply, 0);
            // 获取远程计算结果
            int result = reply.readInt();
            OLog.i(TAG, "result = " + result);
            return result;
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return 0;
    }

   这里我们通过Parcel.ontain()方法创建了data和reply两个Parcel类型的数据,并往data中写入了我们的a和b参数,之后直接调用mBinder的transact方法来调用远程Service的myBinder对象的onTransact方法,需要关注的是,transact的第一个参数我们传入的也是RemoteProtocal.CODE_ADD,需要与onTransact中的code对应起来,第四个参数传入了0,表示该方法是有返回值的。最后我们再从reply里面获取计算后的结果。至此,我们的一次完整的进程间通信工作完成。

测试工程界面如下:


完整工程代码:自定义Binder实现进程间通信







  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值