Android IPC机制绑定Service实现本地通信
**写作原因:跨进程通信的实现和理解是android进阶中重要的一环。下面博主分享ipc一些相关知识、操作及自己在学习ipc过程中的一些理解。
这一章是为下面的messenger和aidl的使用做准备,主要讲解android service的绑定和activity与本地service之间通信相关知识。**
简介
我们都知道启动service有两种方式:startservice()和bindservice()。相比第一种方式,bindservice()能够更加灵活地实现与启动端activity的数据通信,第一种启动方式启动activity与service之间并没有直接关联,难以直接实现通信(当然了,使用broadcast或者事件总线也是可以实现的)。而使用绑定的方式启动service则可以实现service之间的通信。
下面就讲述一下绑定service实现本地通信的流程。
实例
结合图片我们来模拟开启一个后台执行更新功能为例来讲解本地service的绑定。
先分析一下该需求的场景:首先我们需要点击start按钮开启后台更新数据,后台将数据返回给activity并在progressbar展示进度;当我们点击pause时后台暂停更新;点击stop按钮时关闭后台。本例中也用到service通过broadcast向activity传递数据。由于只是实例,对于线程操作一块有一些bug,希望大家能够帮忙指正。
activity的布局如下:
service 实现:
先看看service的实现:
思路是这样的:先继承binder类创建mybinder类,把mybinder看做service与activity通信的代理人,所以在mybinder内部中写好方法间接调用service中的方法以供activity去调用(如本例中callpauseupgrade())。关于ibinder对象的获取除了直接重写后面还有两种方式,这里先不阐述了。在service中我们开启一个thread,在这个thread中模拟持续更新进度条直到isstop为false或者progress大于等于100时,然后将进度广播出去,让activity接收到广播进行进度条更新。service*activity调用的方法实现暂停和停止thread的功能,具体过程参照代码。
public class upgradeservice extends service { private thread thread; private intent intent; private int progress; private boolean isstop; public class mybinder extends binder{ public void callpauseupgrade(){ pauseupgrade(); } public void callstopupgrade() { stopupgrade(); } } private void stopupgrade() { progress = 0; isstop = false; intent.putextra("progress",progress); sendbroadcast(intent); } @override public void oncreate() { super.oncreate(); progress = 0; isstop = true; intent = new intent(); thread = new thread(new runnable() { @override public void run() { while(isstop){ try { thread.sleep(1000); } catch (interruptedexception e) { e.printstacktrace(); } progress = progress +5; intent.putextra("progress",progress); intent.setaction("upgrade_action"); sendbroadcast(intent); if(progress>=100) break; } } }); thread.start(); } private void pauseupgrade() { //todo:pause the upgrade toast.maketext(getapplicationcontext(),"暂停",toast.length_short).show(); isstop = false; } @override public ibinder onbind(intent intent) { return new mybinder(); } }
activity实现
下面是在客户端实现与service的通信代码。主要思路是:先注册广播实现service数据的返回;单击start按钮时实现与service的绑定,创建serviceconnection对象实现serviceconnection接口,分别回调绑定成功和失败两种情况下的逻辑。当成功时获取mybinder对象,并将设置的isbound值设为true;当失败时将isbound设置为false。单击pause调用mybinder对象的callpauseupgrade()方法间接调用service中的pauseupgrade()方法。单击stop调用callstopupgrade()方法并且解除绑定。注意解除绑定事件只能执行一次,否则程序会崩溃。
具体实现并不难,主要是认真理解上面的流程图即可。
public class mainactivity extends appcompatactivity implements view.onclicklistener{ private button mbtstart; private button mbtstop; private button mbtpause; private progressbar mpbprogress; private upgradeservice.mybinder mybinder; private boolean isbound; private upgradereceiver upgradereceiver; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); intentfilter intentfilter = new intentfilter(); intentfilter.addaction("upgrade_action"); upgradereceiver = new upgradereceiver(); registerreceiver(upgradereceiver,intentfilter); initview(); initevent(); } public class upgradereceiver extends broadcastreceiver{ @override public void onreceive(context context, intent intent) { mpbprogress.setprogress(intent.getintextra("progress",0)); } } @override protected void ondestroy() { super.ondestroy(); unregisterreceiver(upgradereceiver); } private void initevent() { mbtpause.setonclicklistener(this); mbtstart.setonclicklistener(this); mbtstop.setonclicklistener(this); } private void initview() { mbtpause = (button) findviewbyid(r.id.bt_pause); mbtstart = (button) findviewbyid(r.id.bt_start); mbtstop = (button) findviewbyid(r.id.bt_stop); mpbprogress = (progressbar) findviewbyid(r.id.pb_progress); } @override public void onclick(view v) { switch(v.getid()){ case r.id.bt_pause: if(isbound&&mybinder!=null){ mybinder.callpauseupgrade(); } break; case r.id.bt_start: bindservice(new intent(mainactivity.this,upgradeservice.class),conn,bind_auto_create); break; case r.id.bt_stop: if(isbound) { mybinder.callstopupgrade(); unbindservice(conn); isbound = false; } break; } } private serviceconnection conn = new serviceconnection() { @override public void onserviceconnected(componentname name, ibinder service) { if(service != null){ mybinder = (upgradeservice.mybinder) service; isbound = true; } } @override public void onservicedisconnected(componentname name) { isbound = false; } }; }
总结:
这篇文章是为下面的messenger和aidl跨进程通信做准备的,实际上个人感觉真正开发时可以使用eventbus或者rxjava取代这种同进程各个组件通信的问题,有兴趣的读者可以自行尝试。
上一篇: Django 前后台的数据传递的方法
下一篇: C++流对象