当前位置: 移动技术网 > IT编程>移动开发>Android > Android中Messenger原理及基本用法详解

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

姚芊羽儿子,世界上美女最多的地方,养生者快读网

这边博客主要记录一下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确实可以在不同进程间传递消息。

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网