自定义接口交互
4何谓自定义接口呢,其实就是我们自己通过接口的实现来达到Activity与Service交互的目的,我们通过在Activity和Service之间架设一座桥樑,从而达到数据交互的目的,而这种实现方式和AIDL非常类似(后文会说到)。
4.1 实现原理
自定义一个接口,该接口中有一个获取当前下载进度的空方法。Server端用一个类继承自Binder并实现该接口,覆写了其中获取当前下载进度的方法。Client端通过ServiceConnection获取到该类的对象,从而能够使用该获取当前下载进度的方法,最终实现实时交互。
4.2 实现步骤
4.2.1 新建一个Interface,并在其中创建一个用于获取当前下载进度的的空方法getCurrentLoad()
publicinterfaceICountService {
publicintgetCurrentLoad();
}
4.2.2 新建Server端DownService实现ICountService并在其中通过一个内部类ServiceBinder继承自Binder并实现ICoutService接口。
publicclassDownLoadServiceextendsServiceimplementsICountService{
privateServiceBinder serviceBinder =newServiceBinder();
publicclassServiceBinderextendsBinderimplementsICountService{
@Override
publicintgetCurrentLoad() {
Log.i(TAG, "ServiceBinder getCurrentLoad()... i=:"+i);
returni;
}
}
@Override
publicintgetCurrentLoad() {
return0;
}
}
在Server端中,实现获取下载进度的空方法getCurrentLoad();这是Eclipse自动生成的,重点不在这裡。我们需要在ServiceBinder类中覆写getCurrentLoad()方法,这裡我们返回当前的下载进度i。
4.2.3 Client端使用bindService()绑定Server端。
if(startSerBtn == v) {
Log.i(TAG, "Start Button Clicked.");
bindService(intent, serConn, BIND_AUTO_CREATE);
timer.schedule(newMyTimerTask(),1000, TIME *1000);//这里一定要延迟一下再开始获取数据,不然会报空指针异常
}
在Client端绑定Server端的同时,延迟1s开始获取下载进度。其中的intent = new Intent(“com.seven.test”);com.seven.test该字符串要与在AndroidManifest.xml中申明的一致
4.2.4 Server端返回binder对象。
@Override
publicIBinder onBind(Intent intent) {
Log.i(TAG, "DownLoadService.onBind()...");
returnserviceBinder;
}
这里的serviceBinder因为继承了Binder因此也是Binder对象。
4.2.5 Client端通过ServiceConnection来获取Server端的binder对象。
privateServiceConnection serConn =newServiceConnection() {
@Override
publicvoidonServiceDisconnected(ComponentName name) {
iCountService = null;
}
@Override
publicvoidonServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "onServiceConnected()...");
iCountService = (ICountService)service;
}
};
获取的过程是在bindService()过程中完成的,这里的iCountService是接口ICountService的对象,在这里得到实例化。
4.2.6 在绑定完成之后,Server端会开启下载,在实际情况中Server端会开启独立线程用于下载,这里用i++来代替。
@Override
publicvoidonCreate() {
super.onCreate();
Log.i(TAG, "DownLoadService.onCreate()...");
timer = newTimer();
timer.schedule(newMyTimerTask(),0, TIME*1000);
}
classMyTimerTaskextendsTimerTask{
@Override
publicvoidrun() {
if(100==i){
i=0;
}
i++;
}
}
bindService()方法执行之后会调用DownLoadService中的onCreate()方法,在其onCreate()方法中开启timer使得i++。
4.2.7 Server端已经开启了下载,那么Client端需要及时获取下载进度并在主界面上更新。
Handler mHandler =newHandler(){
@Override
publicvoidhandleMessage(Message msg) {
super.handleMessage(msg);
Log.i(TAG, "handleMessage...");
intcurLoad = iCountService.getCurrentLoad();
mProgressBar.setProgress(curLoad);
currentTv.setText(curLoad+"%");
}
};
classMyTimerTaskextendsTimerTask{
@Override
publicvoidrun() {
mHandler.sendMessage(mHandler.obtainMessage());
}
}
Client端的Timer在bindService()完成之后1秒再开始获取下载进度,获取方法是直接通过int curLoad = iCountService.getCurrentLoad();这里的getCurrentLoad()方法是DownLoadService内部类ServiceBinder中的方法。Client端将获取到的下载进度更新到介面上并更新进度条。
4.3 小结
通过上面的例子可以知道,这种方法简单实用,扩展性强,但其也有一些缺点,比如需要延迟一些再开始获取Server端的数据,从而无法完全实现从零开始同步更新。综其所述,通过自定义接口实现Activity与Service交互的方法还是比较实用的。适用於同进程中通信,不能进行跨进程通信。