Android跨进程通信(IPC机制 二)

作者: Android_Jian | 来源:发表于2018-09-02 00:34 被阅读23次

    在上个小节中,我们学习了AIDL的基本用法,这里先来回顾一下大致流程:首先创建一个Service和一个AIDL接口,接着创建一个类继承自AIDL中的Sub类并实现Sub类中的抽象方法,在Service中的onBind方法中返回这个类的对象,然后客户端就可以绑定服务端Service,建立连接后就可以访问远程服务端的方法了。

    如果我们的项目中只有一个业务模块需要用到AIDL进行跨进程通信的话,上述方式完全可以应对。但随着我们项目日益庞大,现在有多个业务模块需要进行跨进程通信,该怎么解决呢?当然按照上述方式对每个模块一个一个按部就班也是可以的,不过这样子的话,我们的项目中就会存在多个进程,这显然不是最优的解决方式。我们可不可以只创建一个远程服务端进程来管理多个AIDL呢?答案是可以的,下面我们就一起来学习下Binder连接池。

    为了说明问题,在这里我们提供两个AIDL接口(IDataOne 和 IDataTwo)用来模拟两个业务模块,分别用来处理 数据加减运算和数据乘除运算。声明如下:

    // IDataOne.aidl
    package com.example.administrator.binderpooltest;
    
    interface IDataOne {
        int add(int a, int b);
        int minus(int a, int b);
    }
    
    // IDataTwo.aidl
    package com.example.administrator.binderpooltest;
    
    interface IDataTwo {
       int multiply(int a, int b);
       int divide(int a, int b);
    }
    

    上面两个AIDL接口实现代码如下:

    package com.example.administrator.binderpooltest;
    
    import android.os.RemoteException;
    
    public class DataOneImpl extends IDataOne.Stub{
    
        @Override
        public int add(int a, int b) throws RemoteException {
            return a + b;
        }
    
        @Override
        public int minus(int a, int b) throws RemoteException {
            return a - b;
        }
    }
    
    package com.example.administrator.binderpooltest;
    
    import android.os.RemoteException;
    
    public class DataTwoImpl extends IDataTwo.Stub{
    
        @Override
        public int multiply(int a, int b) throws RemoteException {
            return a * b;
        }
    
        @Override
        public int divide(int a, int b) throws RemoteException {
            return a / b;        // 暂不考虑b为0的情况
        }
    }
    

    现在业务模块的AIDL接口定义和实现都已经完成了,接下来我们来看下服务端和Binder连接池的代码实现:

    首先为Binder连接池创建AIDL接口IBinderPool :

    // IBinderPool.aidl
    package com.example.administrator.binderpooltest;
    
    interface IBinderPool {
        IBinder queryBinder(int binderCode);
    }
    

    接着为Binder连接池创建远程Service并实现IBinderPool ,代码如下:

    package com.example.administrator.binderpooltest;
    
    public class Contat {
        public static final int BINDER_DATA_ONE = 1;
        public static final int BINDER_DATA_TWO = 2;
    }
    
    package com.example.administrator.binderpooltest;
    
    import android.os.IBinder;
    import android.os.RemoteException;
    
    public class BinderPoolImpl extends IBinderPool.Stub{
    
        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {
            IBinder binder = null;
            switch (binderCode){
                case Contat.BINDER_DATA_ONE:
                    binder = new DataOneImpl();
                    break;
    
                case Contat.BINDER_DATA_TWO:
                    binder = new DataTwoImpl();
                    break;
    
                default:
                    break;
            }
            return binder;
        }
    }
    
    package com.example.administrator.binderpooltest;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.Binder;
    import android.os.IBinder;
    import android.support.annotation.Nullable;
    
    public class BinderPoolService extends Service{
    
        private Binder mBinderPool = new BinderPoolImpl();
    
        @Override
        public void onCreate() {
            super.onCreate();
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return mBinderPool;
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
        }
    }
    

    记得Service需要在manifest文件中声明:

    <service 
         android:name=".BinderPoolService"
         android:process=":remote"/>
    

    接下来看下Binder连接池的具体实现:

    package com.example.administrator.binderpooltest;
    
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.IBinder;
    import android.os.RemoteException;
    
    import java.util.concurrent.CountDownLatch;
    
    public class BinderPool {
    
        private static final String TAG = "BinderPool";
    
        private Context mContext;
        private IBinderPool mBinderPool;
        private static volatile BinderPool mInstance;
        private CountDownLatch mCountDownLatch;
    
        private BinderPool(Context context){
            mContext = context.getApplicationContext();
            connectBinderPoolService();
        }
    
        public static BinderPool getmInstance(Context context){
            if (mInstance == null){
                synchronized (BinderPool.class){
                    if (mInstance == null){
                        mInstance = new BinderPool(context);
                    }
                }
            }
            return mInstance;
        }
    
        private synchronized void connectBinderPoolService(){
            mCountDownLatch = new CountDownLatch(1);
            Intent intent = new Intent(mContext,BinderPoolService.class);
            mContext.bindService(intent,mBinderPoolConnection,Context.BIND_AUTO_CREATE);
            try {
                mCountDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public IBinder queryBinder(int binderCode){
            IBinder binder = null;
    
            try {
                if (mBinderPool != null) {
                    binder = mBinderPool.queryBinder(binderCode);
                }
            }catch (RemoteException e){
                e.printStackTrace();
            }
            return binder;
        }
    
        private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mBinderPool = IBinderPool.Stub.asInterface(service);
                try {
                    mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient,0);
                }catch (RemoteException e){
                    e.printStackTrace();
                }
                mCountDownLatch.countDown();
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    
        private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
            @Override
            public void binderDied() {
                if (mBinderPool != null){
                    mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0);
                }
                mBinderPool = null;
                connectBinderPoolService();
            }
        };
    }
    

    下面我们在客户端来验证一下,客户端代码编写如下:

    package com.example.administrator.binderpooltest;
    
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends AppCompatActivity {
    
        private static final String TAG = "MainActivity";
    
        private Button mDataOneTest;
        private Button mDataTwoTest;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initView();
            initListener();
        }
    
        private void initView(){
            mDataOneTest = (Button) findViewById(R.id.mDataOneTest);
            mDataTwoTest = (Button) findViewById(R.id.mDataTwoTest);
        }
    
        private void initListener(){
            mDataOneTest.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            BinderPool binderPool = BinderPool.getmInstance(MainActivity.this);
                            IBinder dataOneBinder = binderPool.queryBinder(Contat.BINDER_DATA_ONE);
                            IDataOne mDataOne = IDataOne.Stub.asInterface(dataOneBinder);
                            try {
                                int addResult = mDataOne.add(2,3);
                                Log.e(TAG,"result 2 + 3 = "+addResult);
                                int minusResult = mDataOne.minus(8,2);
                                Log.e(TAG,"result 8 - 2 = "+minusResult);
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            }
                        }
                    }).start();
                }
            });
    
            mDataTwoTest.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            BinderPool binderPool = BinderPool.getmInstance(MainActivity.this);
                            IBinder dataTwoBinder = binderPool.queryBinder(Contat.BINDER_DATA_TWO);
                            IDataTwo mDataTwo = IDataTwo.Stub.asInterface(dataTwoBinder);
                            try {
                                int multiplyResult = mDataTwo.multiply(2,3);
                                Log.e(TAG,"result 2 * 3 = "+multiplyResult);
                                int divideResult = mDataTwo.divide(8,2);
                                Log.e(TAG,"result 8 / 2 = "+divideResult);
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            }
                        }
                    }).start();
                }
            });
        }
    }
    

    分别点击按钮,测试结果如下:

    09-02 00:18:32.185 17275-18727/com.example.administrator.binderpooltest E/MainActivity: result 2 + 3 = 5
    09-02 00:18:32.185 17275-18727/com.example.administrator.binderpooltest E/MainActivity: result 8 - 2 = 6
    09-02 00:18:33.845 17275-18754/com.example.administrator.binderpooltest E/MainActivity: result 2 * 3 = 6
    09-02 00:18:33.845 17275-18754/com.example.administrator.binderpooltest E/MainActivity: result 8 / 2 = 4
    

    可以看到程序正常运行。由此可见,Binder连接池能够极大提高AIDL的开发效率,并且可以避免大量的Service创建,建议我们在AIDL开发工作中引入BinderPool机制。

    相关文章

      网友评论

        本文标题:Android跨进程通信(IPC机制 二)

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