美文网首页Android
Android Binder的极简使用

Android Binder的极简使用

作者: 未丑 | 来源:发表于2018-06-20 17:17 被阅读0次

    进程间通信很多同学都使用到AIDL,这个是对Binder进行了一层封装。其实剥开AIDL,刺果果的使用Binder,有种很简单的方式,不过最好是系统应用,因为看Android版本的提升,在安全方面一直在完善,不排除以后只能系统权限才能使用这种方式。好了,Read the code~

    服务端,首先要有一个Binder类,然后重写onTransact
    public class MyBinder extends Binder {

    String TAG = "MyBinder";
    private Context context = null;
    
    public MyBinder(Context context) {
        // TODO Auto-generated constructor stub
        this.context = context;
    }
    
    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        
    switch (code) {
        case 0://
                //int len = data.readInt();
                reply.writeInt(1);
            Log.d(TAG, "onTransact case 0");
    return true;
    
        case 1://           
            
    return true;
      }
    
      return super.onTransact(code, data, reply, flags);
    }
    

    }

    接着,搞一个服务,通过反射调用系统方法将其添加到servicemanager,早期Android版本貌似有直接的API,现在都需要反射调用了。

    IBinder mb = new MyBinder(context) ;

        try {
            Class<?>  serviceManager = Class.forName("android.os.ServiceManager");
            Method method=serviceManager.getMethod("addService", String.class, IBinder.class);
            
            method.invoke(null, "testService", mb);
            Log.d(TAG, "add testService to systemservice");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            Log.i(TAG, "add testService fail");
            e.printStackTrace();
        }
    

    服务端差不多就这样了,看看客户端怎么和这个玩意儿通信

    先获取服务,
    try {
    Class<?> serviceManager = Class.forName("android.os.ServiceManager");
    Method method=serviceManager.getMethod("getService", String.class);
    ibinder = (IBinder) method.invoke(null, "testService");
    Log.i("wwwwwww", "get testService success ibinder:"+ibinder);
    } catch (Exception e) {
    // TODO: handle exception
    Log.i("wwwwwww", "get testService fail");
    }

    接着,这样使用
    Parcel data =Parcel.obtain();
    Parcel reply=Parcel.obtain();
    byte[] cmdsetb = {0x02,0x02,0x21,0x44,0x02,0x14,0x09,0x42,0x08,0x00,0x00,0x20};

        data.writeInt(12);
        data.writeByteArray(cmdsetb);
        
        try {
             boolean c = ibinder.transact(0, data, reply, 0);
             int ir = reply.readInt();          
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    

    这就把数据(data)发过去了,然后服务端可以通过replay返回数据;第一个参数是code;最后一个是flags,表示同步或异步。

    是不是比封装AIDL简单。了解AIDL的同学看到上面的代码可能会注意到一点,就是服务端返回数据,即可对应到AIDL的out回传方式。差别在于AIDL是回传引用,所以像上面代码直接往replay写int那样的方式AIDL就做不到了。AIDL的话可以new一个类,传引用回去。

    ============================================================
    客户端和服务端绑定后,可以监听服务端的状态,当服务端因为异常停止后,能收到死亡通知。如下
    直接用binder的linkToDeath

         try {
            ibinder.linkToDeath(deathHandle, 0);
        } catch (RemoteException e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }
    
    final DeathRecipient deathHandle = new DeathRecipient(){
    
        @Override
        public void binderDied() {
            // TODO Auto-generated method stub
            Log.i("wwss", "binder is died");
        }
         
     };
    

    这样,当服务端崩溃的时候,binder断开,即可接收到死亡通知。

    如果是服务端需要监听客户端是否崩溃、被kill呢,又该如何?
    那就有点不同了,因为客户端是不确定的,所以需要客户端注册一个binder进来。

    相关文章

      网友评论

        本文标题:Android Binder的极简使用

        本文链接:https://www.haomeiwen.com/subject/pgyxyftx.html