AIDL灵活运用,避免创建多个Service

来源:互联网 发布:opencv python之间联系 编辑:程序博客网 时间:2024/06/05 15:16

    前面转载了一篇AIDL的入门文章,从那时开始接触的AIDL。

 AIDL的使用一般是一个客户端,一个服务端。服务端返回一个AIDL接口,客户端拿到该接口调用方法。

但是,如果项目中有大量的AIDL文件,那么就要建相应个数的Service,这显然是不合理,现在介绍一种方法,优化AIDL的使用。先帖服务端的目录结构图


MainActivity是默认的,没添加任何代码,直接忽略。首先先看三个AIDL文件,都是很简单的。

ICompute.aidl文件代码为:

interface ICompute {   int add(int a,int b);}
,只定义了一个方法。

ISecurityCenter.aidl文件代码:

interface ISecurityCenter {   String encrypt(String content);   String decrypt(String password);}
,定义两个方法,加密跟解密

IBinderPool.aidl文件代码为:

interface IBinderPool {  IBinder queryBinder(int binderCode);}
,这个是本次博客的重点,通过该接口来达到需要的结果。 服务端返回这个接口给客服端,客服端需要的其他任何接口都是通过调用IBinderPool接口的queryBinder方法返回的。

然后再看三个JAVA类的代码

public class ComputeImpl extends ICompute.Stub {    @Override    public int add(int a, int b) throws RemoteException {        return a+b;    }}
   是AIDL文件ICompute的实现类;

public class SecurityCenterImpl extends Stub{    private static final char SECRET_CODE='^';    @Override    public String encrypt(String content) throws RemoteException {        char[] chars=content.toCharArray();        for (int i = 0; i < chars.length; i++) {            chars[i] ^=SECRET_CODE;        }        return new String(chars);    }    @Override    public String decrypt(String password) throws RemoteException {        return encrypt(password);    }}
       是AIDL文件ISecurityCenter的实现类,这两个类的作用就是实现接口中的方法,以便于客户端调用。BinderPoolService类则是唯一的Service类,客户端就是通过与该Service类绑定从而得到的IBinderPool接口。通过调用IBinderPool这个接口中的queryBinder方法,达到根据传入不同的code得到不同的AIDL接口。

BinderService.java代码:

public class BinderPoolService extends Service {    public static final int BINDER_COMPUTE = 0;    public static final int BINDER_SECURITY_CENTER = 1;    private static final String TAG="BinderPoolService";    private Binder mBinderPool = new IBinderPool.Stub() {        @Override        public IBinder queryBinder(int binderCode) throws RemoteException {            IBinder binder = null;            switch (binderCode) {                case BINDER_SECURITY_CENTER:                    binder = new SecurityCenterImpl();                    break;                case BINDER_COMPUTE:                    binder = new ComputeImpl();                    break;                default:                    break;            }            return binder;        }    };    @Nullable    @Override    public IBinder onBind(Intent intent) {        return mBinderPool;    }    @Override    public void onCreate() {        super.onCreate();    }    @Override    public void onDestroy() {        super.onDestroy();    }}

这个Service类也很简单,首先是实现IBinderPool接口,并实现其中的queryBinder方法,方法中根据不同的binderCode生成不同的AIDL接口,并返回。Service主要是在OnBind方法中IBinderPool接口返回。到此,服务端就完成了,再来看看客服端的代码,也很简单,首先目录结构。写代码前首先把服务端的AIDL文件夹整个拷贝过来。然后看看BinderPool的代码:

public class BinderPool {    private static final String TAG = "BinderPool";    public static final int BINDER_NONE = -1;    public static final int BINDER_COMPUTE = 0;    public static final int BINDER_SECURITY_CENTER = 1;    public Context mContext;    private IBinderPool mBinderPool;    private static volatile BinderPool sInstance;    private CountDownLatch mConnectBinderPoolCountDownLatch;    private BinderPool(Context context) {        mContext = context.getApplicationContext();        connectBinderPoolService();    }    public static BinderPool getInstance(Context context) {        if (sInstance == null) {            synchronized (BinderPool.class) {                if (sInstance == null) {                    sInstance = new BinderPool(context);                }            }        }        return sInstance;    }    private synchronized void connectBinderPoolService() {        mConnectBinderPoolCountDownLatch = new CountDownLatch(1);        Intent intent = new Intent();        intent.setAction("com.lypeer.aidl1");        intent.setPackage("com.example.administrator.aidlserviceone");        mContext.bindService(intent, mBinderPoolConnection, Context.BIND_AUTO_CREATE);        try {            mConnectBinderPoolCountDownLatch.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) {            Log.i("--->","连接成功");            mBinderPool = IBinderPool.Stub.asInterface(service);            try {                mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);            } catch (RemoteException e) {                e.printStackTrace();            }            mConnectBinderPoolCountDownLatch.countDown();        }        @Override        public void onServiceDisconnected(ComponentName name) {            Log.i("--->","连接失败");        }    };    private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {        @Override        public void binderDied() {            mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);            mBinderPool = null;            connectBinderPoolService();        }    };}
这个相当于工具类,负责绑定服务端的Service,以及获取其他的AIDL接口。

MainActivity.java代码:

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new Thread(new Runnable() {                    @Override                    public void run() {                        doWork();                    }                }).start();            }        });    }    private void doWork(){        BinderPool binderPool=BinderPool.getInstance(MainActivity.this);        IBinder securityBinder=binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);        ISecurityCenter mSecurityCenter= ISecurityCenter.Stub.asInterface(securityBinder);        String msg="helloword-安卓";        try {            String password=mSecurityCenter.encrypt(msg);            Log.i("---->",password);        } catch (RemoteException e) {            e.printStackTrace();        }        IBinder computeBinder=binderPool.queryBinder(BinderPool.BINDER_COMPUTE);        ICompute mCompute=ICompute.Stub.asInterface(computeBinder);        try {            Log.i("3+5--->",""+ mCompute.add(3,5));        } catch (RemoteException e) {            e.printStackTrace();        }    }}
主要是执行work方法。

  好了,运行起来看一看吧。如果要添加AIDL问价,只需要在服务端的Service里queryBinder方法中添加一个bindercode,当然还有一点比较重要,就是服务端和客户端要约定好不同的AIDL文件对应不同的一个bindercode,而且两端的bindercode要一致,才能保证一一对应。