上篇我们讲述了进程间通信在Android中的一种独有方式Binder,建议不了解的朋友先去看一下这篇文章,因为我们今天要讲进程间的另外一种通信方式Messenger也是基于Binder的,主不过Google给我们封装好了,可以不使用AIDL就可以简单快速的实现。上篇文章链接:http://blog.csdn.net/u014366923/article/details/49887515
好,接下来我们就看看如何使用Messenger来实现。首先来看一下我们今天要学习的知识:
**1. Messenger是什么;
2. Android中Messenger的简单应用;
3. Messenger原理是什么,Messenger源码解析。**
一、Messenger概念:
先来看一张图
通过这张图我们可以很清楚的了解到了Messenger的通信模型。可以看到,我们可以在客户端发送一个Message给服务端,在服务端的handler中会接收到客户端的消息,然后进行对应的处理,处理完成后,再将结果等数据封装成Message,发送给客户端,客户端的handler中会接收到处理的结果。
其实说白了,它就是封装了Binder,我们不必关系Binder,通过Handler来通信的一种方式。
二、Messenger在Android中的简单应用:
下面我们来看一个小例子,模仿微信聊天,做一个智能机器人的聊天demo。在这个例子中我们使用了当下比较流行的RecyclerView代替传统的ListView。用SwipeRefreshLayout来实现下拉刷新功能。都是Google原生的控件,还是比较综合的一个小案例。
好,我们先来看一下服务端的源码:
public class MyService extends Service{
public static final String SERVICE_KEY = "service_key";
private HandlerThread handlerThread = new HandlerThread("service_handler_thread");
private MyHandler handler;
private Messenger messenger;
@Override
public void onCreate() {
super.onCreate();
handlerThread.start();
handler = new MyHandler(handlerThread.getLooper());
messenger = new Messenger(handler);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
class MyHandler extends Handler{
public MyHandler(Looper looper){
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle obj = (Bundle) msg.obj;
obj.setClassLoader(getClass().getClassLoader());
MessageBean messageBeanFromClient = (MessageBean) obj.getParcelable(SERVICE_KEY);
if(messageBeanFromClient == null){
return;
}
Message message = Message.obtain();
Bundle bundle = new Bundle();
MessageBean messageBeanToClient = new MessageBean();
if ("第一次".equals(messageBeanFromClient.getContent())){
messageBeanToClient.setContent("您好,我是小智");
}else {
messageBeanToClient.setContent("您好,"+messageBeanFromClient.getContent());
}
messageBeanToClient.setClient(false);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
messageBeanToClient.setDate(simpleDateFormat.format(new Date()));
bundle.putParcelable(MainActivity.CLIENT_KEY,messageBeanToClient);
message.obj = bundle;
try {
msg.replyTo.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
我们来简单的读一下源码,首先继承自Android四大组件之一的Service组件,这个没什么好说的,别忘了在AndroidManifest.xml文件中注册我们的服务,在注册的时候不要忘记android:process
属性,若是没有这个属性,那我们的服务就会和客户端在一个进程中,也就谈不上进程间通信了。好,继续来分析源码,可以看到,服务端有一个Messenger类型的对象,在构造过程中我们传递了一个Handler对象。在Handler对象的handleMessage中我们来处理客户端发给我们的消息,并且再发回给客户端。其实就是:服务端中有一个依赖于Handler的Messenger的对象,通过Handler消息循环模型,Messenger可以发送消息给客户端。在onBind
方法中可以看到return messenger.getBinder();
是不是突然明白点什么了呢。。。。。。
客户端源码:
public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {
public static final String CLIENT_KEY = "client_key";
private SwipeRefreshLayout mSwipeRefreshLayout;
private RecyclerView mRecyclerView;
private EditText et_content;
private Messenger mService;
private ArrayList<MessageBean> list;
private MessageAdapter messageAdapter;
private boolean isConnet = false;
private Messenger mMessenger = new Messenger(new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle obj = (Bundle) msg.obj;
obj.setClassLoader(getClass().getClassLoader());
list.add((MessageBean) obj.getParcelable(CLIENT_KEY));
messageAdapter.notifyDataSetChanged();
mRecyclerView.smoothScrollToPosition(list.size() - 1);
}
});
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
isConnet = true;
mService = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private LinearLayoutManager mLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StatusBarCompat.compat(this,getResources().getColor(R.color.colorPrimaryDark));
initView();
bindService();
}
private void bindService() {
Intent intent = new Intent(this,MyService.class);
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
}
private void initView() {
mSwipeRefreshLayout = (SwipeRefreshLayout) this.findViewById(R.id.swipe_refresh_layout);
mRecyclerView = (RecyclerView) this.findViewById(R.id.recycler_view);
mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary, R.color.colorPrimaryDark,R.color.colorAccent);
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setProgressViewOffset(false, 0, (int) TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, getResources()
.getDisplayMetrics()));
mSwipeRefreshLayout.setRefreshing(true);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
// mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));
Toolbar mToolBar = (Toolbar) this.findViewById(R.id.toolbar);
mToolBar.setTitle("智能聊天机器人");
mToolBar.setTitleTextColor(Color.WHITE);
et_content = (EditText) this.findViewById(R.id.edit_text_content);
list = new ArrayList<MessageBean>();
messageAdapter = new MessageAdapter(this,list,mRecyclerView);
mRecyclerView.setAdapter(messageAdapter);
}
@Override
public void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
sendMessage("第一次");
mSwipeRefreshLayout.setRefreshing(false);
}
},2000);
}
public void sendMessageToService(View view){
String content = et_content.getText().toString().trim();
if (isConnet && !TextUtils.isEmpty(content)) {
MessageBean m = sendMessage(content);
list.add(m);
messageAdapter.notifyDataSetChanged();
et_content.setText("");
mRecyclerView.smoothScrollToPosition(list.size() - 1);
//InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
// inputManager.hideSoftInputFromWindow(et_content.getWindowToken(),0);
}
}
@Nullable
private MessageBean sendMessage(String content) {
Message message = Message.obtain();
MessageBean messageBean = new MessageBean();
messageBean.setContent(content);
messageBean.setClient(true);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
messageBean.setDate(simpleDateFormat.format(new Date()));
Bundle bundle = new Bundle();
bundle.putParcelable(MyService.SERVICE_KEY, messageBean);
message.obj = bundle;
try {
message.replyTo = mMessenger;
mService.send(message);
return messageBean;
} catch (RemoteException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onDestroy() {
super.onDestroy();
isConnet = false;
unbindService(serviceConnection);
}
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mSwipeRefreshLayout.setRefreshing(false);
}
},2000);
}
}
客户端源码比较简单了,我们来重点看几段代码:
private void bindService() {
Intent intent = new Intent(this,MyService.class);
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
}
绑定我们的服务端Service,相信大家都懂得,在
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
isConnet = true;
mService = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
在这里我们看到又创建了一个Messenger对象,我滴神额,咋又创建了一个,仔细一看,构造方法参数还不一样,服务端我们创建的时候是传入了一个Handler对象,这里好像是一个IBinder对象诶 ~(≧▽≦)/~ 泪奔中……, 先不要慌,我们继续来看代码,细心的朋友可以看到其实我们客户端是有两个Messenger对象的,oh my god!!! 。加上服务端的不是又三个对象吗,是的 确实是有三个Messenger对象。我们来梳理一下逻辑吧,可能有些朋友要疯…………o(>﹏<)o。
按照上面的模型图,要想实现这样的通信方式,服务端和和客户端必须要各自有一个Messenger对象才行,要不然没法发送消息啊!客户端只有把自己的Messenger对象给服务端,服务端把自己的Messenger对象给客户端,这样在双方中都会有彼此的引用对象,才可以发送消息,是不是呢~,至于为什么客户端要有两个Messenger对象,是因为客户端是主动发起方,它必须要先拿到服务端Messenger对象才行,这里你可以把这个Messenger对象理解为服务端的Messenger。
三、源码解析:
好,我们来看一下Messenger的内部源码到底什么怎样的,首先看一下通过Handler对象构建的构造方法,也就是服务端的Messenger创建过程。
/**
* Create a new Messenger pointing to the given Handler. Any Message
* objects sent through this Messenger will appear in the Handler as if
* {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
* been called directly.
*
* @param target The Handler that will receive sent messages.
*/
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
可以看到这里通过Handler对象返回了一个mTarget对象,那mTarget对象是什么呢,我们找到mTarget的声明private final IMessenger mTarget;
它是一个IMessenger类型的对象。我们继续看一下target.getIMessenger();内部是什么样的,继续跟进去:
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
这里创建了一个 MessengerImpl类型的对象,来看看MessengerImpl是什么:
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
它是Handler的一个内部类,实现了IMessenger.Stub
接口,等等…… 我怎么看着这么眼熟呢,没错,我们之前用Binder的时候也有一个类实现了xxxxx.Stub接口。莫非~没错,你想的没错,它和我们之前用的是一样的。它同样对应一个AIDL文件。再回想一下我们服务端的onBinder方法,messenger.getBinder();
我们看看这个方法内部
/**
* Retrieve the IBinder that this Messenger is using to communicate with
* its associated Handler.
*
* @return Returns the IBinder backing this Messenger.
*/
public IBinder getBinder() {
return mTarget.asBinder();
}
这下明白了吧,和我们之前用的Binder不是一样嘛,对不对,嘿嘿,是不是有种~。。。。。。,
我们继续看一下客户端源码:
我们重点看一下serviceConnection中的
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
isConnet = true;
mService = new Messenger(service);
}
看一下用IBinder 对象创建的Messenger过程:
/**
* Create a Messenger from a raw IBinder, which had previously been
* retrieved with {@link #getBinder}.
*
* @param target The IBinder this Messenger should communicate with.
*/
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
这里可以看到和我们之前写的几乎一模一样,无非就是Messenger更进一步封装了而已。
最后我们来看一下发送消息的过程:
无论是服务端还是客户端发送消息都是用的Messenger的send方法,
/**
* Send a Message to this Messenger's Handler.
*
* @param message The Message to send. Usually retrieved through
* {@link Message#obtain() Message.obtain()}.
*
* @throws RemoteException Throws DeadObjectException if the target
* Handler no longer exists.
*/
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
再调用的IMessenger的send方法,其实就是Handler里面创建的MessengerImpl的send方法,我们看到在MessengerImpl的send方法里面调用了Handler的sendMessage方法。这样就可以通过Handler的消息循环模型来接收,发送消息了,进而实现了进程间的通信。说白了,Messenger通信方式就是Handler+Binder。
最后来一张效果图:
源码地址:
https://github.com/qqxliufeng/MessengerTestProject