Messenger实现了IPC通信(进程间通信),其真实原理也是使用了AIDL进行通信,但是和直接使用AIDL不同的是Messenger利用了Handler处 理通信,所以它是线程安全的(不支持并发处理);
而我们平时用的AIDL是非线程安全的(支持并发处理)。所以大多数时候我们应用中是不需要处理夸进程并 发处理通信的,所以这时选择Messenger会比AIDL更加容易操作。
在不考虑并发的情况下,Messenger相比AIDL无论从代码量、工程结构、复杂度等上都更加胜出一筹
信使 代码的服务端:
//这个里面要注意自己的Messenger对象的创建是以Handler为构造参数的,而接受到的对方的Messenger则是以Binder为构造参数的(在客户端),在服务端接受的Messenger对象则是从消息中直接获取。
要在清单文件中注册服务:
public
class
MainActivity
extends
Activity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.
activity_main
);
}
@Override
public
boolean
onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.
main
, menu);
return
true
;
}
}
public
class
PrintService
extends
Service {
//1. 声明和实例化Handler及Messenger类对象,在这个方法中处理客户端发送过来的信息
private
static
Handler
mHandler
=
new
Handler(){
@Override
public
void
handleMessage(Message msg) {
//处理其它线间或进程发送过来的消息
Log. i(
"debug"
,
"--PrintService ---------------------->handleMessage:"
+msg.getData().getString(
"info"
));
Message replyMsg=Message. obtain();
replyMsg.
what
=2;
try
{
//msg.replyTo 是获取到客户端传递过来的Messenger对象。,然后用客户端自己的Messenger对象,在给客户端发送消息。
msg.
replyTo
.send(replyMsg);
//应答客户端: 向客户端回传消息
}
catch
(RemoteException e) {
e.printStackTrace();
}
}
};
//创建本地的Messenger,以handler为构造参数。
private
Messenger
messenger
=
new
Messenger(
mHandler
);
@Override
public
IBinder onBind(Intent intent) {
return
messenger
.getBinder();
//2.获取Messenger对象的IBinder接口对象
}
}
布局文件:
<
RelativeLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
xmlns:tools
=
"http://schemas.android.com/tools"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:paddingBottom
=
"@dimen/activity_vertical_margin"
android:paddingLeft
=
"@dimen/activity_horizontal_margin"
android:paddingRight
=
"@dimen/activity_horizontal_margin"
android:paddingTop
=
"@dimen/activity_vertical_margin"
tools:context
=
".MainActivity"
>
<
TextView
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"@string/hello_world"
/>
</
RelativeLayout
>
------------------------
信使客户端:
布局文件:
<
RelativeLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
xmlns:tools
=
"http://schemas.android.com/tools"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:paddingBottom
=
"@dimen/activity_vertical_margin"
android:paddingLeft
=
"@dimen/activity_horizontal_margin"
android:paddingRight
=
"@dimen/activity_horizontal_margin"
android:paddingTop
=
"@dimen/activity_vertical_margin"
tools:context
=
".MainActivity"
>
<
Button
android:id
=
"@+id/btnId"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:onClick
=
"send"
android:text
=
"项服务端发送消息"
/>
</
RelativeLayout
>
主界面代码:
/*
* 基于Messenger实现应用间的线程间通信
* 1.客户端:
* 声明Messenger对象
* 声明并实例化SerViceConnection 接口对象 ,在绑定服务组件时使用,用于监听绑定是否成功
* 在合适的位置调用Context.bindService()方法进行绑定
* 在 ServiceConnection接口 的onServiceConnected()方法中
* 将方法的第二个参数作为实例化Messenger的构造方法参数使用
* 在核实的位置,调用Messenger对象的send(Message msg) 项服务端的Handler中发送消息
*
* 2.
* 2) 如果客户端需要接收服务端回传或应答的消息,需要实例化Handler和Messenger,
* 并将Messenger作为服务端应答的信使封装在向服务端发送的Message(消息)中
*/
public
class
MainActivity
extends
Activity {
//1. 声明Messenger对象,这个对象是从服务端发送过来的Messenger对象。
private
Messenger
messenger
;
//2. 实例化ServiceConnection接口对象
private
ServiceConnection
conn
=
new
ServiceConnection(){
@Override
public
void
onServiceConnected(ComponentName name, IBinder service) {
//
TODO
绑定成功的回调方法
//4.实例化Messenger对象,并使用当前方法的第二个参数,传入到Messenger构造方法中。这个Messenger对象是从服务端发送过来的。
messenger
=
new
Messenger(service);
}
@Override
public
void
onServiceDisconnected(ComponentName name) {
//
TODO
Auto-generated method stub
}
};
private
Handler
replyHandler
=
new
Handler(){
@Override
public
void
handleMessage(Message msg) {
//接收服务端回传的消息
if
(msg.
what
==2){
Toast. makeText(getApplicationContext(),
"发送消息成功.."
, 1).show();
}
}
};
//这个是客户端自己的信使,这个信使的作用是要被传递到服务端,在给客户端发送消息
private
Messenger
replyMessenger
=
new
Messenger(
replyHandler
);
//应答信使
@Override
protected
voi d
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.
activity_main
);
//3.开始绑定服务组件
bindService(
new
Intent(
"com.mrl.messenger_server.PrintService"
),
conn
,
BIND_AUTO_CREATE
);
}
public
void
send(View v){
//5. 通过Messenger信使,向绑定服务组件所在的应用发送消息(由这一应用的Handler来处理的)
Message msg=Message. obtain();
//进程间传递的信息必须实现Parcelable接口 ,一般如果要传递对象什么的,应该通过Bundle来传递不会抛异常。
//msg.obj="hello,Messenger~Server"; //此处会抛出异常,原因是String类没有实现 Parcelable接口
Bundle data=
new
Bundle();
data.putString(
"info"
,
"hello,Messenger~Server"
);
msg.setData(data);
//设置发送消息的数据
//设置服务端应答信使,将客户端的信使作为消息发送给服务端
msg.
replyTo
=
replyMessenger
;
try
{
//这个Messenger是服务端发送过来的Messenger对象,现在往服务端发送消息。
messenger
.send(msg);
//通过信使开始向外部应用发送消息
}
catch
(RemoteException e) {
e.printStackTrace();
}
}
}
-----------------------------------------------------
aidl的创建于使用:
先在服务端的src下创建一个包,新建一个 .aidl文件。如下图:
aidl文件的写法:
package com.mrl.aidl;
interface IRemoteService{//接口名不能用public 修饰
void print(String
msg
);
String getName();
}
在服务端的配置文件中配置service组件:
<!-- 注册Service组件,注:此组件可被其应用访问,因此必须要提供一个Action -->
<
service
android:name
=
"com.mrl.serviceaidl_server.RemoteService"
>
<
intent-filter
>
<
action
android:name
=
"com.mrl.serviceaidl_server.RemoteService"
/>
</
intent-filter
>
</
service
>
将服务端的aidl文件连同包一块拷贝到客户端。
下面是代码实例:
客户端主界面:
/**
* 通过AIDL方式绑定其它应用的服务组件
*
@author
apple
*
*/
public
class
MainActivity
extends
Activity {
//声明aild接口对象
IRemoteService
remoteService
;
//实例化绑定组件之间的通信接口
ServiceConnection
conn
=
new
ServiceConnection() {
@Override
public
void
onServiceDisconnected(ComponentName name) {}
@Override
public
void
onServiceConnected(ComponentName name, IBinder service) {
//将第二个参数转化为. aidl接口对象
remoteService
=IRemoteService.Stub.asInterface(service);
}
};
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.
activity_main
);
//绑定其它应用的Service组件,在绑定成功之后,将返回的Stub对象转化为 aidl接口对象
bindService(
new
Intent(
"com.mrl.serviceaidl_server.RemoteService"
),
conn
,
BIND_AUTO_CREATE
);
}
public
void
getRemoteName(View v)
throws
RemoteException{
if
(
remoteService
!=
null
){
setTitle(
remoteService
.getName());
}
}
public
void
print(View v)
throws
RemoteException{
if
(
remoteService
!=
null
){
remoteService
.print(
"hello,service!!!"
);
}
}
}
服务端主界面:
/**
* 使用AIDL原理,实现进程间(应用间)的Service组件与Activity组件的通信
* 1) 服务端
* 1.声明. aidl文件,在此文件中声明进程间的通信接口(类似于Binder子类的作用)
* 2.在Service组件的onBind()方法中,返回 aidl接口的Stub对象
* 3. 注册Service组件是,必须要提供一个启动或绑定此组件的Action
*
* 2) 客户端
* 1. 将服务端提供的. aidl文件复制到src下
* 2. 在Activity类中,实例化ServiceConnection接口对象,实现两个回调方法,
* 在onServiceConnected()方法中将第二个参数转化. aidl接口对象
* 3. 在适当的位置调用Context.bindService()方法,进行绑定
*
* 此方法的第一个参数:Intent意图,在实例化时,需要指定Service组件的Action
*
*
*
@author
apple
*
*/
public
class
MainActivity
extends
Activity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.
activity_main
);
}
@Override
public
boolean
onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.
main
, menu);
return
true
;
}
}
public
class
RemoteService
extends
Service {
//2.1 实例化.aidl接口的Stub对象
private
IRemoteService.Stub
stub
=
new
IRemoteService.Stub() {
@Override
public
void
print(String msg)
throws
RemoteException {
Log. i(
"debug"
,
"--RemoteSerice---------------------------"
+msg);
// Looper.prepare();
// 这个操作会有问题:
// Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
// Looper.loop();
}
// cant't create handler inside thread that has has not called Looper.prepare()
//only one looper may be created per thread at android.os.looper.prepare
@Override
public
String getName()
throws
RemoteException {
// Looper.prepare();
// 这个问题同样有错
// Toast.makeText(getApplicationContext(), "RemoteSerice", Toast.LENGTH_SHORT).show();
// Looper.loop();
return
"RemoteSerice--------"
;
}
};
@Override
public
IBinder onBind(Intent intent) {
return
stub
;
//2.2 返回 aidl接口的Stub对象
}
}
-------------------------------------------