本篇主要介绍内容
1、Binder连接池
先来回顾一下AIDL的大致流程
1、首先创建一个Service和AIDL接口;
2、创建一个类继承AIDL接口中的Stub类,并实现其中抽象方法;
3、在Service的onBind方法中返回这个对象;
4、客户端绑定服务端获取到这个对象就可以访问服务器的方法了;
以上就是典型的AIDL的执行流程,现在有这样一个问题:一个项目越来越庞大,现在有10个不同的业务模块都需要使用AIDL来实现,那么要怎么办呢?按照AIDL的方式一个个来实现?如果按照这种方式,那么我们就要创建10个Service。如果是100个呢?到这里应该明白,随着我们的业务不断增加,AIDL也要不断增加,这就导致了我们要无限制的增加Service;Service本身是一种资源,如果一个应用有十几个Service运行,极大的消耗内存资源,影响应用的性能;那么应该怎么办呢?有没有一种方式创建一个Service就能解决这个问题呢?答案是肯定的,就是我们今天要介绍的主角:Binder连接池;
什么是Binder连接池
按照上面我们提的需求,服务端有10个不同的业务模块,每个模块我们都创建相应的AIDL接口和实现,然后这些不同业务模块的Binder对象统一由Binder连接池来管理,客户端可以根据不同编码或唯一标识来获取相应模块的Binder对象;Binder连接池主要用来管理和查询相应的Binder对象,具体流程如下图所示:
接下来我们用一个实例来实现Binder连接池,场景是这样的,我们在服务端定义了两个aidl接口,分别是做加法和乘法的计算(当然可以增加更多接口),客户端通过Binder连接池来调用服务器的方法;
首先是服务端:
定义两个aidl的接口
// IMyAdd.aidl
package test.jiao.com.aidl;
interface IMyAdd {
int add(int first,int second);
}
// IMyRide.aidl
package test.jiao.com.aidl;
interface IMyRide {
int ride(int first, int second);
}
然后实现这两个aidl接口:
package test.jiao.com.aidl;
import android.os.RemoteException;
/**
* date :2016/12/30
* author :SuperJiao
* Description
*/
public class MyAddImpl extends IMyAdd.Stub {
@Override
public int add(int first, int second) throws RemoteException {
return first + second;
}
}
package test.jiao.com.aidl;
import android.os.RemoteException;
/**
* date :2016/12/30
* author :SuperJiao
* Description
*/
public class MyRideImpl extends IMyRide.Stub {
@Override
public int ride(int first, int second) throws RemoteException {
return first * second;
}
}
接下来实现我们的Binder连接池,首先定义Binder连接池的aidl接口
// IBinderPool.aidl
package test.jiao.com.aidl;
interface IBinderPool {
IBinder getIBinder(int binderCode);
}
我是根据code来判断用户查询哪个接口,并返回相应的服务的,你也可以用其他方式来查询,这个可以根据需求灵活变换;
接下来我们来实现这个aidl接口
package test.jiao.com.aidl;
import android.os.IBinder;
import android.os.RemoteException;
/**
* date :2016/12/30
* author :SuperJiao
* Description
*/
public class BinderPoolImpl extends IBinderPool.Stub {
@Override
public IBinder getIBinder(int binderCode) throws RemoteException {
IBinder mBinder = null;
switch (binderCode) {
case ContentPool.POOL_ADD:
mBinder = new MyAddImpl();
break;
case ContentPool.POOL_RIDE:
mBinder = new MyRideImpl();
break;
}
return mBinder;
}
}
可以看出来,服务端所有aidl的接口的实现,都是在连接池中创建出来的,客户端只需要根据code来获取相应的方法即可;
接下来我们只需要创建一个服务在onbind中将该连接池的Binder对象返回即可;
package test.jiao.com.aidl;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class BinderPoolService extends Service {
private Binder mBinderPool = new BinderPoolImpl();
@Override
public IBinder onBind(Intent intent) {
return mBinderPool;
}
}
然后是客户端,客户端的核心代码主要是连接池的具体实现;
首先客户端要和服务端一致创建一样的aidl接口,可以看上方服务端的代码;
客户端的aidl接口如下
接下来就是客户端的核心连接池的实现:
package test.jiao.com.aidl;
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;
/**
* date :2016/12/30
* author :SuperJiao
* Description
*/
public class BinderPool {
private Context mContext;
private static volatile BinderPool sInstance;
private IBinderPool mBinderPool;
private BinderPool(Context context) {
mContext = context;
}
public static BinderPool getInstance(Context context) {
if (sInstance == null) {
synchronized (BinderPool.class) {
if (sInstance == null) {
sInstance = new BinderPool(context);
}
}
}
return sInstance;
}
//绑定服务
public synchronized void connectBinderPoolService() {
Intent intent = new Intent();
intent.setAction("com.jiao.myaidl.action.BINDERPOOL_SERVICE");
mContext.bindService(intent, mBinderPoolConnection, Context.BIND_AUTO_CREATE);
}
//解绑服务
public void disConnectBinderPoolService() {
mContext.unbindService(mBinderPoolConnection);
}
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();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
//服务死亡监听
private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);
mBinderPool = null;
connectBinderPoolService();
}
};
//根据code获取相应的Binder对象
public IBinder getBinder(int code) {
IBinder binder = null;
switch (code) {
case ContentPool.POOL_ADD://加法
try {
binder = mBinderPool.getIBinder(ContentPool.POOL_ADD);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case ContentPool.POOL_RIDE://乘法
try {
binder = mBinderPool.getIBinder(ContentPool.POOL_RIDE);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
return binder;
}
}
可以看出来,客户端的连接池类,主要用来绑定服务端的服务,然后获取到服务端返回的连接池Binder对象,通过这个对象就可以连接服务器获取服务端的其他aidl接口的binder对象,通过这个Binder对象就可以调取服务端相应的方法;
接下来我们来验证一下,我们创建一个Activity,有两个按钮,一个是乘法计算一个是加法计算;点击相应的按钮得到相应的计算结果,代码如下:
package test.jiao.com.aidl;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity implements View.OnClickListener {
private Button bt_aidl_add;
private Button bt_aidl_ride;
private BinderPool binderPool;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start();
}
private void start() {
bt_aidl_ride = (Button) findViewById(R.id.bt_aidl_ride);
bt_aidl_add = (Button) findViewById(R.id.bt_aidl_add);
bt_aidl_add.setOnClickListener(this);
bt_aidl_ride.setOnClickListener(this);
binderPool();
}
private void binderPool() {
binderPool = BinderPool.getInstance(this);
binderPool.connectBinderPoolService();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_aidl_ride:
IMyRide iMyRide = IMyRide.Stub.asInterface(binderPool.getBinder(ContentPool.POOL_RIDE));
try {
Toast.makeText(this, iMyRide.ride(5, 5) + "", Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.bt_aidl_add:
IMyAdd iMyAdd = IMyAdd.Stub.asInterface(binderPool.getBinder(ContentPool.POOL_ADD));
try {
Toast.makeText(this, iMyAdd.add(5, 5) + "", Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
@Override
protected void onDestroy() {
binderPool.disConnectBinderPoolService();
super.onDestroy();
}
}
运行结果如下:
Paste_Image.png这样,无论服务端有多少个aidl接口,我们只需要扩展连接池就可以了,避免了创建更多的Service,大大的提升了程序的效率;
最后我们再来总结一下:在Android中的IPC机制最主要的方式有AIDL、Messenger、ContentProvider、Socket等;无论哪种方式,底层都是用Binder来实现的;本篇取其中最基本、通用的一种方式AIDL来讲解主要是要大家弄明白Android中的进程间通信的原理和具体实现,到这里,相信大家对Android的IPC机制和AIDL的实现已经有了进一步的了解;关于其他的方式,有兴趣的小伙伴可以自己探究一下;
网友评论