欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-03-04 16:02:41
**写作原因:跨进程通信的实现和理解是android进阶中重要的一环。下面博主分享ipc一些相关知识、操作及自己在学习ipc过程中的一些理解。 这一章是为下面的mess...

**写作原因:跨进程通信的实现和理解是android进阶中重要的一环。下面博主分享ipc一些相关知识、操作及自己在学习ipc过程中的一些理解。
这一章是为下面的messenger和aidl的使用做准备,主要讲解android service的绑定和activity与本地service之间通信相关知识。**

简介

我们都知道启动service有两种方式:startservice()和bindservice()。相比第一种方式,bindservice()能够更加灵活地实现与启动端activity的数据通信,第一种启动方式启动activity与service之间并没有直接关联,难以直接实现通信(当然了,使用broadcast或者事件总线也是可以实现的)。而使用绑定的方式启动service则可以实现service之间的通信。 

 下面就讲述一下绑定service实现本地通信的流程。

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

实例

 结合图片我们来模拟开启一个后台执行更新功能为例来讲解本地service的绑定。

 先分析一下该需求的场景:首先我们需要点击start按钮开启后台更新数据,后台将数据返回给activity并在progressbar展示进度;当我们点击pause时后台暂停更新;点击stop按钮时关闭后台。本例中也用到service通过broadcast向activity传递数据。由于只是实例,对于线程操作一块有一些bug,希望大家能够帮忙指正。

activity的布局如下:

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

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取代这种同进程各个组件通信的问题,有兴趣的读者可以自行尝试。