当前位置: 移动技术网 > 移动技术>移动开发>Android > Android IPC机制绑定Service实现本地通信

Android IPC机制绑定Service实现本地通信

2019年07月24日  | 移动技术网移动技术  | 我要评论
**写作原因:跨进程通信的实现和理解是android进阶中重要的一环。下面博主分享ipc一些相关知识、操作及自己在学习ipc过程中的一些理解。 这一章是为下面的mess

**写作原因:跨进程通信的实现和理解是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取代这种同进程各个组件通信的问题,有兴趣的读者可以自行尝试。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网