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

Android中Messenger原理及基本用法详解

程序员文章站 2023-11-12 21:34:10
这边博客主要记录一下android中messenger的基本原理和用法。 简单来讲,messenger其实就是binder通信的包装器,是一种基于消息传递的进程间通信工具...

这边博客主要记录一下android中messenger的基本原理和用法。

简单来讲,messenger其实就是binder通信的包装器,是一种基于消息传递的进程间通信工具。

//messenger实现了parcelable接口,因此可以跨进程传输
public final class messenger implements parcelable {
 ...............
}

通常情况下,我们可以在a进程中创建一个messenger,然后将该messenger传递给b进程。
于是,b进程就可以通过messenger与a进程通信了。

messenger通常与handler一起使用,我们看看对应的源码:

public final class messenger implements parcelable {
 private final imessenger mtarget;

 public messenger(handler target) {
  mtarget = target.getimessenger();
 }
 ...........
}

跟进一下handler的getimessenger函数:

 .............
 final imessenger getimessenger() {
  synchronized (mqueue) {
   if (mmessenger != null) {
    return mmessenger;
   }
   //返回的是handler中定义的messengerimpl
   mmessenger = new messengerimpl();
   return mmessenger;
  }
 }

 //此处messengerimpl继承自imessenger.stub
 //容易看出messengerimpl将作为binder通信的接收端
 private final class messengerimpl extends imessenger.stub {
  public void send(message msg) {
   msg.sendinguid = binder.getcallinguid();
   handler.this.sendmessage(msg);
  }
 }

从上述代码可以看出,messenger实际上作为了一个binder服务端的wrapper。

当我们在a进程中创建messenger,然后传递给b进程时,messenger需要执行parcelable接口定义的操作,于是:

 //在a进程中将binder信息写入到parcel中
 public void writetoparcel(parcel out, int flags) {
  out.writestrongbinder(mtarget.asbinder());
 }

 public static final parcelable.creator<messenger> creator
   = new parcelable.creator<messenger>() {
  //在b进程中,重新创建binder
  public messenger createfromparcel(parcel in) {
   ibinder target = in.readstrongbinder();

   //调用messenger的另一个构造函数
   return target != null ? new messenger(target) : null;
  }

  public messenger[] newarray(int size) {
   return new messenger[size];
  }
 };

跟进一下messenger的另一个构造函数:

public messenger(ibinder target) {
 //得到的是binder通信的客户端
 mtarget = imessenger.stub.asinterface(target);
}

因此,当messenger从进程a传递到进程b时,它就变为了binder通信客户端的wrapper。

当在进程b中使用messenger的接口时:

public void send(message message) throws remoteexception {
 //mtarget为binder通信的客户端,将消息发送给服务端的send函数
 //即服务端handler的messengerimpl的send函数
 //上文已经附上了对应代码,可以看到对应的消息将递交给handler处理
 mtarget.send(message);
}

以上就是messenger通信的原理,现在实际测试一下。
我们定义一个简单的demo,包含一个activity和一个service,其中service与activity处在不同的进程中。

androidmanifest.xml中的定义如下:

  .....................
  <activity android:name=".mainactivity">
   <intent-filter>
    <action android:name="android.intent.action.main"/>

    <category android:name="android.intent.category.launcher"/>
   </intent-filter>
  </activity>

  <service
   android:name=".remoteservice"
   android:enabled="true"
   android:exported="true"
   <!--指定服务运行在其它进程-->
   android:process=".remote">
  </service>
  ..............

activity的界面很简单,当点击时就会像service发送消息,activity代码如下:

public class mainactivity extends appcompatactivity {
 private button mbutton;

 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_main);

  //打印activity的pid及所在进程名称
  log.d("zjtest", "activity, pid: " + process.mypid() +
    ", name: " + util.getprocessname(this));

  //启动服务
  startservice();

  //绑定服务
  bindservice();

  mbutton = (button) findviewbyid(r.id.test_button);
  mbutton.setenabled(false);
  //点击按键后,利用messenger向service发送消息
  mbutton.setonclicklistener(new view.onclicklistener() {
   @override
   public void onclick(view v) {
    if (mmessenger != null) {
     try {
      message msg = message.obtain();
      msg.what = 1;
      mmessenger.send(msg);
     } catch (remoteexception e) {
      log.d("zjtest", e.tostring());
     }
    }
   }
  });
 }

 @override
 public void ondestroy() {
  super.ondestroy();
  unbindservice();
  stopservice();
 }

 private intent mintent;
 private void startservice() {
  mintent = new intent(this, remoteservice.class);
  this.startservice(mintent);
 }

 private serviceconnection mserviceconnection;
 private void bindservice() {
  mserviceconnection = new localserviceconnection();
  this.bindservice(mintent, mserviceconnection, bind_auto_create);
 }

 messenger mmessenger;
 private class localserviceconnection implements android.content.serviceconnection {
  @override
  public void onserviceconnected(componentname name, ibinder service) {
   //绑定服务后,获得messenger并激活button
   mmessenger = new messenger(service);
   mbutton.setenabled(true);
  }

  @override
  public void onservicedisconnected(componentname name) {
   mbutton.setenabled(false);
  }
 }

 private void stopservice() {
  stopservice(mintent);
 }

 private void unbindservice() {
  unbindservice(mserviceconnection);
 }
}

service对应的代码如下:

public class remoteservice extends service {
 private messenger mmessenger;

 @override
 public void oncreate() {
  super.oncreate();

  //同样打印进程号及名称
  log.d("zjtest", "service, pid: " + process.mypid()
    + ", name: " + util.getprocessname(this));

  localhandler mhandler = new localhandler();

  mmessenger = new messenger(mhandler);
 }

 private static class localhandler extends handler{
  @override
  public void handlemessage(message msg) {
   log.d("zjtest", "receive msg: " + msg.what);
  }
 }

 @override
 public ibinder onbind(intent intent) {
  //被绑定时,返回messenger
  return mmessenger.getbinder();
 }
}

获取进程名的代码如下:

class util {
 static string getprocessname(context context) {
  int pid = process.mypid();
  activitymanager am = (activitymanager) context
    .getsystemservice(context.activity_service);

  for (activitymanager.runningappprocessinfo appprocessinfo:
    am.getrunningappprocesses()) {
   if (appprocessinfo.pid == pid) {
    return appprocessinfo.processname;
   }
  }

  return null;
 }
}

上述代码都是比较简单的,现在来看看运行结果:

02-20 21:25:15.760 d/zjtest  (30460): activity, pid: 30460, name: stark.a.is.zhang.messengertest
02-20 21:25:15.769 d/zjtest  (30428): service, pid: 30428, name: .remote
02-20 21:25:32.111 d/zjtest  (30428): receive msg: 1

从log可以看出,activity与servie运行在不同的进程中,messenger确实可以在不同进程间传递消息。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。