美文网首页Android知识Android技术知识Android开发
极简开发 -- 进程间通讯框架非AIDL(IPCCommunic

极简开发 -- 进程间通讯框架非AIDL(IPCCommunic

作者: j春雨 | 来源:发表于2017-03-24 16:34 被阅读659次

    IPCCommunication github地址

    进程间通信

    说到Android进程间通信,大家肯定能想到的是编写aidl文件,然后通过aapt生成的类方便的完成服务端,以及客户端代码的编写。

    什么是IPCCommunication

    IPCCommunication是通过两种方式实现进程间通信,一种是手写binder实现进程间通信,互相传递使用Bunder,可以在Bunder中自定义协议,另外一种是基于Message,客户端与服务端之间使用Message进行通信;

    为什么要写这个框架

    曾经听过一个人说过,程序中尽量使用通用组件或者框架,这样可以尽量的少写代码,这样有两个好处,一是少写代码就意味着少犯错误,二是可以多出喝咖啡的时间 ;

    使用

    手写Binder方式有两种方式
    1.使用通用的IPCService服务库,包括与Activity通信
    服务端
    服务端可以通过Activity 启动也可以不启动,若不启动可以通过继承BaseIPCService的方式,具体实现查看SimpleService

    public class MainActivity extends AppCompatActivity {
    
        private ServiceUtils mServiceUtils;
        private static final String TAG = "jcy_service";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mServiceUtils = new ServiceUtils(this);
        }
    
    
        @Override
        protected void onResume() {
            super.onResume();
            //调用默认IPC 服务
            mServiceUtils.setConnectListener(mConnectListener);
            mServiceUtils.bindService();
        }
    
    
        @Override
        protected void onStop() {
            super.onStop();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            mServiceUtils.unBindService();
        }
    
        ConnectListener mConnectListener = new ConnectListener() {
    
            @Override
            public void onBind() {
            }
    
            @Override
            public void onDisconnected() {
    
            }
    
            @Override
            public void onConnected(boolean success) {
                mServiceUtils.setReceiverListener(mReceiverListener);
            }
    
            @Override
            public void onUnbind() {
                mServiceUtils.setReceiverListener(null);
            }
    
            ;
        };
    
        private ReceiverListener mReceiverListener = new ReceiverListener() {
            @Override
            public Bundle receiveInfo(int code, Bundle msg) {
                String msgStr = msg.getString("msgStr");
                int msgInt = msg.getInt("msgInt");
                Log.d(TAG, "receiveInfo: msgStr " + msgStr + "   ,msgInt : " + msgInt);
                Bundle ret = new Bundle();
                ret.putString("return", "服务端返回  code " + code + " ,msgStr " + msgStr + "   ,msgInt : " + msgInt);
                return ret;
            }
        };
    }
    

    客户端

    public class MainActivity extends AppCompatActivity  {
    
        private static final String TAG = "jcy_client_one";
        private TextView mTextView;
        private TextView tv_state;
        private ClientUtils mClientUtils;
        private Button btnGet, btn_bind, btn_unbind;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mTextView = (TextView) findViewById(R.id.tv_service);
            tv_state = (TextView) findViewById(R.id.tv_state);
            btnGet = (Button) findViewById(R.id.btn_getService);
            btn_bind = (Button) findViewById(R.id.btn_bind);
            btn_unbind = (Button) findViewById(R.id.btn_unbind);
            btnGet.setEnabled(false);
            tv_state.setText("  服务未绑定 ");
            mClientUtils = new ClientUtils(this);
            mClientUtils.setConnectListener(mConnectListener);
            btn_bind.setEnabled(true);
            btn_unbind.setEnabled(false);
        }
    
        @Override
        protected void onResume() {
            super.onResume();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if(mClientUtils!=null){
                mClientUtils.unBindService();
            }
        }
    
        /**
         * 获取数据
         *
         * @param v
         */
        public void onGetServie(View v) {
            if (mClientUtils.isConnect()) {
                Bundle send = new Bundle();
                send.putString("msgStr", "ClientOneApp发送消息");
                send.putInt("msgInt", 110);
                try {
                    Bundle ret = mClientUtils.send(110, send);
                    if (ret == null) {
                        Log.e(TAG, "onGetServie:  ret==null");
                    } else {
                        String retStr = ret.getString("return");
                        mTextView.append("\n"+retStr);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Log.e(TAG, "onGetServie:Exception   " + e.toString());
                }
            } else {
                Toast.makeText(this, "未连接服务,无法获取消息", Toast.LENGTH_SHORT).show();
            }
        }
    
    
        /**
         * 绑定服务
         * @param v
         */
        public void onBindServie(View v) {
            mClientUtils.bindService();
        }
    
        /**
         * 解除绑定
         * @param v
         */
        public void onUnBindServie(View v) {
            mClientUtils.unBindService();
        }
    
    
    
        /**
         * 连接状态回调
         */
        private ConnectListener mConnectListener = new ConnectListener() {
            @Override
            public void onBind() {
                tv_state.setText("  服务正在绑定中…… ");
            }
    
            @Override
            public void onDisconnected() {
                btnGet.setEnabled(false);
                tv_state.setText("  服务断开连接 ");
                btn_bind.setEnabled(true);
                btn_unbind.setEnabled(false);
            }
    
            @Override
            public void onConnected(boolean success) {
                if (success) {
                    tv_state.setText("  服务绑定成功 ");
                    btn_bind.setEnabled(false);
                    btn_unbind.setEnabled(true);
                    btnGet.setEnabled(true);
                } else {
                    btnGet.setEnabled(false);
                    tv_state.setText("  服务绑定失败 ");
                    mClientUtils.unBindService();
                    btn_bind.setEnabled(true);
                    btn_unbind.setEnabled(false);
                }
            }
    
            @Override
            public void onUnbind() {
                btn_bind.setEnabled(true);
                btn_unbind.setEnabled(false);
                tv_state.setText("  服务已解除绑定 ");
                mTextView.setText("");
            }
        };
    
    }
    

    另外还支持自定义Service 的方式 具体查看SimpleService类
    Message的使用方式与自定义Binder的形式类似,大部分使用方式几乎相同

    分析

    手写Binder

    Binder.png

    这个图是盗用别人的嘿嘿;
    首先Activity通过调用bindService去绑定一个远程的服务(Service),绑定成功后返回一个IBinder对象。这时候双方就算是建立了连接了。
    建立连接之后,双方就可以通过持有的IBinder进行通信。Activity使用IBinder的transact方法去给底层的Binder Driver(Linux层)发送消息间接调用底层的IBinder的execTransact方法。
    而execTransact导致的结果就是调用onTransact方法。那么这时候事件的处理就可以在该环节进行了。
    上层主要使用 这个方法进行通信 处理消息;

    public boolean onTransact(int code, android.os.Parcel data, 
    android.os.Parcel reply, int flags) 
    

    这个方法 一般情况下 都是返回true的,也只有返回true的时候才有意义,如果返回false了 就代表这个方法执行失败,onTransact 这个方法 就是运行在Binder线程池中的,一般就是客户端发起请求,然后android底层代码把这个客户端发起的,请求 封装成3个参数 来调用这个onTransact方法,第一个参数code 就代表通信的标志位,data就是方法参数(客户端传递过来的数据),reply就是方法返回值(通过这个方法可以向客户端中返回数据)。

    自定义Binder为

    /**
         * description : 自定义Binder实现消息传递
         * autour      : 姜春雨@沈阳
         * date        : 17-3-24 上午10:33
         * mail        : 1055655886@qq.com
         */
        public class IPCBinder extends Binder {
    
            /**
             *  处理消息
             * @param code 识别码
             * @param data 调用transact的对象传送过去的参数
             * @param reply 调用onTransact的对象返回的参数
             * @param flags Java里面默认的native方法都是阻塞的,当不需要阻塞的时候设置为IBinder.FLAG_ONEWAY,否则设置为0
             * @return
             * @throws RemoteException
             */
            @Override
            protected boolean onTransact(final int code, final Parcel data, final Parcel reply, final int flags) throws RemoteException {
                data.enforceInterface(Contant.DESCRIPTOR);
                Bundle bundle = dealMessage(code,data.readBundle());
                reply.writeNoException();
                reply.writeBundle(bundle);
                return true;
            }
    
            /**
             * 获取当前Service,用于与Service通信
             * @return
             */
            public BaseIPCService getService(){
                return BaseIPCService.this;
            }
        }
    
    

    暂时还未找到如何实现异步通信

    客户端发送消息

    private ServiceConnection conn = new ServiceConnection() {
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                // TODO Auto-generated method stub
                Log.d(TAG, "---  onServiceDisconnected   --- ");
                connect = false;
                if (mConnectListener != null) {
                    mConnectListener.onDisconnected();
                }
            }
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                // TODO Auto-generated method stub
                if (service == null) {
                    connect = false;
                    Log.d(TAG, "---  onServiceConnected  failed service == null   ---");
                    if (mConnectListener != null) {
                        mConnectListener.onConnected(false);
                    }
                } else {
                    Log.d(TAG, "---  onServiceConnected  sucessed   ---");
                    connect = true;
                    if (mConnectListener != null) {
                        mConnectListener.onConnected(true);
                    }
                    mIBinder = service;
                }
            }
        };
    

    连接成功后通过可以获取到Binder对象
    发送消息使用 mIBinder.transact(code, _data, _reply, 0);

     /**
         * 向服务端发送消息
         * @param code 消息类型
         * @param bundle 消息体
         * @return 返回值为服务器的返回
         * @throws Exception
         */
        public Bundle send(int code, Bundle bundle) throws Exception {
            if (mIBinder == null) {
                throw new NullPointerException("IBinder is Null");
            }
            Bundle result = null;
            Parcel _data = Parcel.obtain();
            Parcel _reply = Parcel.obtain();
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                _data.writeBundle(bundle);
                mIBinder.transact(code,
                        _data, _reply, 0);
                _reply.readException();
                result = _reply.readBundle();
            } catch (Exception e) {
                e.printStackTrace();
                throw new Exception(e);
            } finally {
                _reply.recycle();
                _data.recycle();
                return result;
            }
        }
    

    Message通信

    服务端的onBind是这么写的:

    public IBinder onBind(Intent intent)
        {
            return mMessenger.getBinder();
        }
    

    那么点进去:

    public IBinder getBinder() {
            return mTarget.asBinder();
        }
    

    可以看到返回的是mTarget.asBinder();

    mTarget是哪来的呢?

    HandlerThread mHandlerThread = new HandlerThread("BaseMsgIPCService");
                mHandlerThread.start();
                Handler mHandler= new Handler(mHandlerThread.getLooper()){
                    @Override
                    public void handleMessage(Message msgfromClient)
                    {
                        super.handleMessage(msgfromClient);
                    }
                };
                mMessenger= new Messenger(mHandler);
    
     public Messenger(Handler target) {
            mTarget = target.getIMessenger();
        }
    

    原来是Handler返回的,我们继续跟进去

        final IMessenger getIMessenger() {
            synchronized (mQueue) {
                if (mMessenger != null) {
                    return mMessenger;
                }
                mMessenger = new MessengerImpl();
                return mMessenger;
            }
        }
    
         private final class MessengerImpl extends IMessenger.Stub {
            public void send(Message msg) {
                msg.sendingUid = Binder.getCallingUid();
                Handler.this.sendMessage(msg);
            }
        }
    

    mTarget是一个MessengerImpl对象,那么asBinder实际上是返回this,也就是MessengerImpl对象;
    客户端
    客户端首先通过onServiceConnected拿到sevice(Ibinder)对象,这里没什么特殊的,我们平时的写法也是这样的,只不过我们平时会这么写:
    IMessenger.Stub.asInterface(service)拿到接口对象进行调用;
    而,我们的代码中是
    mService = new Messenger(service);
    跟进去,你会发现:

    public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }
    

    和我们平时的写法一模一样!
    到这里就可以明白,客户端与服务端通信,实际上和我们平时的写法没有任何区别,通过编写aidl文件,服务端onBind利用Stub编写接口实现返回;客户端利用回调得到的IBinder对象,使用IMessenger.Stub.asInterface(target)拿到接口实例进行调用。
    (2)服务端与客户端通信
    那么,客户端与服务端通信的确没什么特殊的地方,我们完全也可以编写个类似的aidl文件实现;那么服务端是如何与客户端通信的呢?
    还记得,客户端send方法发送的是一个Message,这个Message.replyTo指向的是一个mMessenger,我们在Activity中初始化的。
    那么将消息发送到服务端,肯定是通过序列化与反序列化拿到Message对象,我们看下Message的反序列化的代码:

    # Message
    private void readFromParcel(Parcel source) {
            what = source.readInt();
            arg1 = source.readInt();
            arg2 = source.readInt();
            if (source.readInt() != 0) {
                obj = source.readParcelable(getClass().getClassLoader());
            }
            when = source.readLong();
            data = source.readBundle();
            replyTo = Messenger.readMessengerOrNullFromParcel(source);
            sendingUid = source.readInt();
        }
    

    主要看replyTo,调用的是Messenger.readMessengerOrNullFromParcel

    public static Messenger readMessengerOrNullFromParcel(Parcel in) {
            IBinder b = in.readStrongBinder();
            return b != null ? new Messenger(b) : null;
        }
    
        public static void writeMessengerOrNullToParcel(Messenger messenger,
                Parcel out) {
            out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder()
                    : null);
        }
    

    通过上面的writeMessengerOrNullToParcel可以看到,它将客户端的messenger.mTarget.asBinder()对象进行了恢复,客户端的message.mTarget.asBinder()是什么?
    客户端也是通过Handler创建的Messenger,于是asBinder返回的是:

    public Messenger(Handler target) {
            mTarget = target.getIMessenger();
        }
     final IMessenger getIMessenger() {
            synchronized (mQueue) {
                if (mMessenger != null) {
                    return mMessenger;
                }
                mMessenger = new MessengerImpl();
                return mMessenger;
            }
        }
    
        private final class MessengerImpl extends IMessenger.Stub {
            public void send(Message msg) {
                msg.sendingUid = Binder.getCallingUid();
                Handler.this.sendMessage(msg);
            }
        }
    
       public IBinder getBinder() {
            return mTarget.asBinder();
        }
    

    那么asBinder,实际上就是MessengerImpl extends IMessenger.Stub
    中的asBinder了。

    #IMessenger.Stub
    
    @Override 
    public android.os.IBinder asBinder()
    {
    return this;
    }
    

    那么其实返回的就是MessengerImpl对象自己。到这里可以看到message.mTarget.asBinder()其实返回的是客户端的MessengerImpl对象。
    最终,发送给客户端的代码是这么写的:

    msgfromClient.replyTo.send(msgToClient);
    
    public void send(Message message) throws RemoteException {
            mTarget.send(message);
        }
    

    这个mTarget实际上就是对客户端的MessengerImpl对象的封装,那么send(message)(屏蔽了transact/onTransact的细节),这个message最终肯定传到客户端的handler的handleMessage方法中。
    Message源码分析部分摘抄自鸿洋_的博客

    欢迎大家follow,star,如果发现bug,希望您能够及时联系我

    IPCCommunication github地址

    相关文章

      网友评论

        本文标题:极简开发 -- 进程间通讯框架非AIDL(IPCCommunic

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