【Android - IPC】之Messenger简介
参考资料:
1、《Android开发艺术探索》第二章2.4.3
1、Messenger概述
Messenger,译为“信使”,是Android中一种基于Binder机制的IPC(Inter-Process Communication,进程间通信)方式。通过Messenger可以在不同进程中传递Message对象,在Message中放入我们需要传递的数据,就可以轻松的实现进程间数据的传递了。即:Messenger允许实现基于消息的进程间通信的方式。
Messenger是一种轻量级的IPC方案,其实现底层是AIDL。
Messenger一次只能处理一个请求,因此在服务端我们不用考虑线程同步的问题,这是因为服务端不存在并发执行的情形。
使用Messenger进行进程间通信的具体流程是:客户端发送一个Message给服务端,在服务端的Handler中接收到客户端的消息,然后进行对应的处理,处理完成后再将结果等数据封装成Message对象,发送给客户端,客户端的Handler中会接收到服务端传过来的数据并进行处理。
2、Messenger通信实例
在这个例子中,客户端的界面上有一个按钮,通过点击这个按钮,向服务端发送两个参数,服务端将这两个参数相加后回传给客户端,客户端收到答案之后显示到界面上。
2.1、服务端
服务端的需要新建一个Service,命名为MessengerService,代码如下:
package my.itgungnir.server; import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.support.annotation.Nullable; /**
* Messenger 服务端Service
* Created by ITGungnir on 2017/4/5.
*/
public class MessengerServer extends Service {
private static final int MSG_GETSUM = 0x001; // Messenger对象,其中的Handler用来接收从客户端传过来的Message,通过可以创建Message对象回传给客户端
Messenger mMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msgFromClient) {
// 要回传给客户端的Message对象
Message msgToClient = Message.obtain(msgFromClient);
switch (msgFromClient.what) {
case MSG_GETSUM:
msgToClient.what = MSG_GETSUM;
try {
Thread.sleep(2000); // 模拟耗时
msgToClient.arg2 = msgFromClient.arg1 + msgFromClient.arg2;
// Message的replyTo也是一个Messenger对象
msgFromClient.replyTo.send(msgToClient);
} catch (Exception e) {
e.printStackTrace();
}
break;
}
super.handleMessage(msgFromClient);
}
}); @Nullable
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder(); // 获取Messenger中的IBinder对象
}
}
可以看到,服务端要做的工作是手动创建一个Messenger,然后在onBind()方法中返回这个Messenger对象的getBinder()对象。
在创建的Messenger中,参数是一个Handler,即从客户端向服务端发送消息时,就是将消息发送到了这个Handler对象中。因此,我们需要在这个Handler对象中处理客户端传过来的消息,当然也可以创建一个新的消息,返回给客户端。
因为服务端使用了Android四大组件中的Service,因此需要在Menifest文件中进行注册,代码如下:
<service android:name=".MessengerServer">
<intent-filter>
<action android:name="my.itgungnir.messenger.getsum" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
2.2、客户端
在客户端中需要做的事情比服务端多。首先,我们需要先绑定到服务端的服务上,然后才可以向服务端请求服务。下面是客户端首页MainActivity.java类中的代码:
package my.itgungnir.client; import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final int MSG_GETSUM = 0x001; private LinearLayout container; // 盛放所有算术题的TextView的容器(LinearLayout)
private TextView state; // 显示服务器连接状态的TextView
private Button require; // 向服务端请求算术题答案的按钮 private Messenger mService; // 客户端的Messenger对象
private boolean isConnected; // 指示是否连接到服务端
private int mArg1 = 0; // 算术题的被加数,同时也是TextView的id @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
bindToServer();
} // 初始化界面中的布局,并绑定相应的事件
private void initViews() {
container = (LinearLayout) findViewById(R.id.client_ly_container);
state = (TextView) findViewById(R.id.client_tv_connection);
require = (Button) findViewById(R.id.client_btn_require);
require.setOnClickListener(this);
} // 获取服务端绑定状态的ServiceConnection对象
private ServiceConnection connection = new ServiceConnection() {
@Override // 绑定服务端成功时回调的方法
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger(service);
isConnected = true;
state.setText("Server Connected!");
} @Override // 绑定服务端失败时回调的方法
public void onServiceDisconnected(ComponentName name) {
mService = null;
isConnected = false;
state.setText("Server Not Connected!");
}
}; // 绑定到服务端
private void bindToServer() {
Intent intent = new Intent();
intent.setAction("my.itgungnir.messenger.getsum");
// Android 5.0 及以上的设备需要为intent设置package,否则会报错:Service Intent must be explicit
intent.setPackage("my.itgungnir.server");
bindService(intent, connection, Context.BIND_AUTO_CREATE);
} // 客户端的Messenger对象
private Messenger mMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msgToClient) {
switch (msgToClient.what) {
case MSG_GETSUM:
// 接收服务端回传的数据并在Handler中更新UI
TextView tv = (TextView) findViewById(msgToClient.arg1);
tv.setText(tv.getText() + " ==> " + msgToClient.arg2);
break;
}
super.handleMessage(msgToClient);
}
}); // 每点击一次按钮,就向服务端发送一条消息
@Override
public void onClick(View v) {
try {
int arg1 = ++mArg1;
int arg2 = (int) (Math.random() * 90 + 10);
TextView tv = new TextView(MainActivity.this);
tv.setTextSize(18f);
tv.setText(arg1 + " + " + arg2 + " = Calculating... ");
tv.setId(arg1);
container.addView(tv);
// 要发送到服务端的Message对象
Message msgFromClient = Message.obtain(null, MSG_GETSUM, arg1, arg2);
msgFromClient.replyTo = mMessenger;
if (isConnected) {
// 将消息发送给服务端Messenger的Handler对象
mService.send(msgFromClient);
}
} catch (RemoteException e) {
e.printStackTrace();
}
} @Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
}
从代码中可以看到,调用bindService()方法之后,在ServiceConnection对象的回调方法中的onServiceConnected()方法(连接服务端成功的回调方法)中,会携带一个IBinder类型的参数,这个参数就是服务端的服务对象,我们可以通过 new Messenger(service) 方法获取到服务端的Messenger对象,然后就可以通过这个Messenger对象,向服务端的Handler发送消息了。
布局文件activity_main.xml文件中的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/client_ly_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="15.0dip"> <TextView
android:id="@+id/client_tv_connection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textSize="20.0sp"
android:textStyle="bold" /> <Button
android:id="@+id/client_btn_require"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15.0dip"
android:layout_marginTop="15.0dip"
android:text="Send Message To Server" /> </LinearLayout>
2.3、运行结果
先运行服务端,再运行客户端,如果连接服务端成功,客户端的状态TextView中会显示 connected 字样;此时我们点击客户端中的按钮,向服务端发送算术题,然后等待服务端计算后将结果返回给客户端。
运行结果如下图所示:
3、 总结
从上面的例子中,我们大致可以看出Messenger的工作机制:
主要是客户端向服务端发送消息请求服务,服务端接收到客户端的请求后提供相应的服务,然后将服务结果封装成消息对象回传给客户端,客户端收到服务端的回传结果对其进行处理使用(如更新UI界面)。
这里需要注意的有三点:
- Messenger中的send()方法:这个方法的作用是将一个Message对象发送给调用这个方法的Messenger的Handler对象(就是new Messenger的时候参数中传入的Handler对象);
- Message对象有一个Messenger类型的replyTo属性,这个属性指定了这条消息的回传对象。在上面的例子中,我们在客户端指定了发送给服务端的Message的replyTo属性是客户端的Messenger,这样在服务端才更容易的拿到客户端的具体的Messenger对象并进行消息的回传;
- Messenger的底层实现是AIDL,其机制也和AIDL相同。
【Android - IPC】之Messenger简介的更多相关文章
- android IPC及原理简介
什么是Android操作系统,所谓的Android:是基于Linux内核的软件平台和操作系统,早期由Google开发,后由开放手机联盟Open Handset Alliance)开发. Linux ...
- android IPC通信(上)-sharedUserId&&Messenger
看了一本书,上面有一章解说了IPC(Inter-Process Communication,进程间通信)通信.决定结合曾经的一篇博客android 两个应用之间的通信与调用和自己的理解来好好整理总结一 ...
- Android Programming: Pushing the Limits -- Chapter 7:Android IPC -- Messenger
Messenger类实际是对Aidl方式的一层封装.本文只是对如何在Service中使用Messenger类实现与客户端的通信进行讲解,对Messenger的底层不做说明.阅读Android Prog ...
- 【Android - IPC】之Binder机制简介
参考资料: 1.<Android开发艺术探索>第二章2.3.3 Binder 2.[Android Binder设计与实现-设计篇] 3.[Android Binder机制介绍] 1. 什 ...
- Android Programming: Pushing the Limits -- Chapter 7:Android IPC -- ApiWrapper
前面两片文章讲解了通过AIDL和Messenger两种方式实现Android IPC.而本文所讲的并不是第三种IPC方式,而是对前面两种方式进行封装,这样我们就不用直接把Aidl文件,java文件拷贝 ...
- Android IPC 结篇
一.概述 Android 的 IPC 方式有 Bundle .共享文件.AIDL .Messenger .ContentProvider .Socket ,我们在实现进程间通信时要选择哪一种方式来实现 ...
- Android IPC机制(三)在Android Studio中使用AIDL实现跨进程方法调用
在上一篇文章Android IPC机制(二)用Messenger进行进程间通信中我们介绍了使用Messenger来进行进程间通信的方法.可是我们能发现Messenger是以串行的方式来处理client ...
- Android IPC(inter-process Communitcation)
Android IPC(inter-process Communitcation) http://www.cnblogs.com/imlucky/archive/2013/08/08/3246013. ...
- 【转】Android 防破解技术简介
http://www.cnblogs.com/likeandroid/p/4888808.html Android 防破解技术简介 这几年随着互联网的不断发展,Android App 也越来越多!但是 ...
- GitHub Android Librarys Top 100 简介
GitHub Android Librarys Top 100 简介 本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据GitHub搜索J ...
随机推荐
- http和Https简介、详解
目录 引用 一.HTTP和HTTPS的基本概念 二.HTTP与HTTPS有什么区别? 三.HTTPS的工作原理 四.HTTPS的优点 五.HTTPS的缺点 六.http切换到HTTPS 引用 超文本传 ...
- Spring Boot (日志篇):Log4j2整合ELK,搭建实时日志平台
一.安装JDK1.8以上版本 1.从Oracle官网上下载Linux x64版本的 下载地址: http://www.oracle.com/technetwork/java/javase/downlo ...
- CAT客户端如何从Apollo中读取配置?
运行环境 以下就是这个示例的运行环境,如果版本号不一样,区别也应该不会很大,可以根据实际情况做相应调整. JDK 8 spring boot 2.0.7.RELEASE cat-client 3.0. ...
- STL库学习笔记(一)——什么是STL?
小明是一个很牛逼的程序员,在国际标准化组织工作. 他现在正在设计新一代的C++标准,标准中有一个待实现的函数:findMax(),这个函数要求使用者输入任何类型的数据,他都能找到最大的一个. 于是他想 ...
- 正睿OI集训游记
什么嘛....就是去被虐的... 反正就是难受就是了.各种神仙知识点,神仙题目,各式各样的仙人掌..... 但是还是学会了不少东西...... 应该是OI生涯最后一次集训了吧.... 这次的感言还是好 ...
- 总结:一些使用private 构造方法的类
第一个,就是单例模式,虽然分为"懒汉模式"和"醉汉模式",但在jvm中有且只有这样的一个对象!这样才能称为单例(详细请参照设计模式) 第二个,工具类,建义工具类 ...
- 《JS高程》-教你如何写出可维护的代码
1.前言 在平时工作开发中,大部分开发人员都花费大量的时间在维护其他人员的代码.很难从头开始开发新代码,很多情况下都是以他人成果为基础的,或者新增修改需求,自己写的代码也会被其他开发人员调用,所以 ...
- vue ui九宫格、底部导航、新闻列表、跨域访问
一. 九宫格 九宫格:在mint-ui组件库基于vue框架 mui不是基于vue框架 只是css/js文件 (1)官方网站下载安装包 (2)copy css js fonts[字体图标] src/l ...
- docker项目——搭建飞机大战小游戏
项目2:搭建打飞机小游戏,验证数据持久化(最底下有链接) 第一步:拉取镜像 [root@localhost docker-image]# docker load < httpd_img.tar. ...
- windows系统cmd命令行窗口查看端口占用情况
# 查看所有在用端口 netstat -ano # 查看指定端口 netstat -ano | findstr 8899 # 结束该进程:taskkill /f /t /im javaw.exe:或者 ...