Android进程间通信(3)-Messenger实现
来源:互联网 发布:seo英语编辑 编辑:程序博客网 时间:2024/06/03 19:04
前面两篇文章中已经介绍了两种实现进程间通信的方式,那是不是只有这两种方式实现进程间通信呢?当然不是,还有更好的实现方式,那就是Messenger。本篇文章将带领大家一起来学习下Messenger.
- 基于aidl实现的进程通信
- 基于纯代码实现的进程通信
没有看我写的上面两篇文章的同学,建议先去看下上面两篇文章,以更好的理解。
什么是基于消息的进程通信?
该图片是引用自弘扬大神的博客
其实基于消息的进程通信就是客户端通过Handler发送一条Message,服务端收到这条Message然后获取到客户端的值,服务端进行处理,再将结果封装成Message传递给客户端。通过这种方式实现aidl有什么好处呢?
- 不用再写aidl文件了(很多同学一提到aidl就头疼)
- 基于Message,这个大家已经很熟悉了
接下来我们通过代码详细的介绍下。
1,服务端,我们定义一个MessengerService.java的Service,代码如下:
package com.wms.github.aidl.server;import android.app.Service;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.util.Log;/** * Created by 王梦思 on 2017/5/25. */public class MessengerService extends Service { private static final String TAG = "MessengerService"; private Messenger messenger = new Messenger(new Handler() { @Override public void handleMessage(Message clientMsg) { if (clientMsg.what == 0x001) { //注意这个里clientMsg是客户端发送过来的消息 Bundle bundle = (Bundle) clientMsg.obj; String str = bundle.getString("str"); str = str.toUpperCase(); //服务端处理完逻辑后,将数据通过Messeage的方式传递给客户端 Message message = Message.obtain(); Bundle sendBundle = new Bundle(); sendBundle.putString("str", str); message.obj = sendBundle; message.what = 0x001; try { //将消息发送到客户端 clientMsg.replyTo.send(message); } catch (RemoteException e) { e.printStackTrace(); } } super.handleMessage(clientMsg); } }); @Override public IBinder onBind(Intent intent) { Log.e(TAG, "onBind..."); //这里不能返回null,必须要返回我们创建的Binder对象 return messenger.getBinder(); } @Override public boolean onUnbind(Intent intent) { Log.e(TAG, "onUnbind..."); return super.onUnbind(intent); } @Override public void onStart(Intent intent, int startId) { Log.e(TAG, "onStart..."); super.onStart(intent, startId); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e(TAG, "onStartCommand..."); return super.onStartCommand(intent, flags, startId); } @Override public void onCreate() { Log.e(TAG, "onCreate..."); super.onCreate(); } @Override public void onDestroy() { Log.e(TAG, "onDestroy..."); super.onDestroy(); }}
服务端就一个Service,可以看到代码相当的简单,只需要去声明一个Messenger对象,然后onBind方法返回messenger.getBinder();
然后坐等客户端将消息发送到handleMessage想法,根据message.what去判断进行什么操作,然后做对应的操作,最终将结果通过 clientMsg.replyTo.send(),这里注意一定要调用clientMsg.replyTo.send()去发送消息,不然客户端接收不到。
注册MessengerService
<service android:name="com.wms.github.aidl.server.MessengerService" android:exported="true"> <intent-filter> <action android:name="com.wms.github.aidl.server.MessengerService"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service>
2,客户端。在客户端我新建一个MessengerActivity.java,代码如下:
package com.wms.github.aidl.client;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.util.Log;import android.view.View;import android.widget.EditText;/** * Created by 王梦思 on 2017/5/25. */public class MessengerActivity extends MainActivity { private EditText mEditText; private Messenger mService; private Messenger clientMessenger = new Messenger(new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 0x001) { Bundle bundle = (Bundle) msg.obj; mEditText.setText(bundle.getString("str")); } super.handleMessage(msg); } }); private ServiceConnection mServiceConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //当绑定成功后调用 Log.e("MainActivity", "onServiceConnected..."); mService = new Messenger(service); } @Override public void onServiceDisconnected(ComponentName name) { Log.e("MainActivity", "onServiceDisconnected..."); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mEditText = (EditText) findViewById(R.id.id_edittext); findViewById(R.id.bind).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { bindService(); } }); findViewById(R.id.unbind).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { unBindService(); } }); findViewById(R.id.invokeServer).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { invokeServer(); } }); } /** * 绑定服务 */ public void bindService() { Intent intent = new Intent(); intent.setAction("com.wms.github.aidl.server.MessengerService"); //Android 5.0以上必须要加这句代码,不然报错 intent.setPackage("com.wms.github.aidl.server"); bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE); } public void unBindService() { unbindService(mServiceConn); } public void invokeServer() { String inputStr = mEditText.getText().toString().trim(); try { Message message = Message.obtain(); message.what = 0x001; Bundle bundle = new Bundle(); bundle.putString("str",inputStr); message.obj = bundle; //将消息的回应设置为clientMessenger,这样客户端发送消息就能在客户端收到了。 message.replyTo = clientMessenger; mService.send(message); } catch (RemoteException e) { //这里会抛出远程异常 e.printStackTrace(); } }}
布局文件和上篇文章中一样。
MessengerActivity.java中代码也很简单,就是绑定一个服务,然后再onServiceConnect中实例化一个Messenger,这个Messenger和MessengerActivity中属性clientMessenger不一样,因为这个Messenger实例化的时候把Binder驱动传递进来了。所以当客户端调用mService.send(message);
后,服务端将会收到客户端传递过来的数据,服务端处理完之后,返回到Client端的clientMessenger中的Handler的handleMessage方法中,这样就完成了客户端和服务端的通信。
效果图:
当我们点击调用服务端转换后,服务端就把大写字母回传给客户端。以上就是简单的Messenger的使用,肯定很多人有疑问,为什么这样可以实现进程间的通信呢?下面我将带领大家一起来从源码的角度来看看。
1,先分析服务端,服务端中onBind()方法里面我们返回了messenger.getBinder();
很简单,就一行代码,我们进入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(); }
getBinder方法也很简单,也就一行代码。这里mTarget是什么呢?查看下源码,private final IMessenger mTarget;
可以看出mTarget是一个IMessenger对象,mTarget赋值是在我们实例化clientMessenger对象的时候Messenger构造方法里面。我们再来看看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内部的getImessenger方法
final IMessenger getIMessenger() { synchronized (mQueue) { if (mMessenger != null) { return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; } }
恍然大悟,原来mTarget其实是一个MessengerImpl对象。再回到Messenger中的getBinder方法,其实就是调用了MessengerImpl内部的asBinder方法,我们进入到MessengerImpl中的asBinder中看看其内部做了什么事情。
MessengerImpl原来是继承自IMessenger.Stub,是不是很熟悉?这不又回到了我们前面的文章中通过aidl实现进程通信的了么?原来Android内部已经帮我们实现了一个IMessenger.aidl文件,这个文件位于framework中的platform_frameworks_base/core/java/android/os/IMessenger.aidl,大家可以下载framework源代码去查看下。由于aidl代码较少,我下面贴出IMessenger.aidl内部代码如下:
package android.os;import android.os.Message;/** @hide */oneway interface IMessenger { void send(in Message msg);}
哇,好简答,就一个send方法,send方法里面传递的是一个Message对象。所以这一切又回到了我们前面所说的aidl进行进程通信的内容了。如果不明白的可以看我之前写过的一篇文章 基于aidl实现的进程通信
2,接下来我们分析下客户端源代码
当客户端调用绑定服务的时候,会调用onServiceConnect方法
private ServiceConnection mServiceConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //当绑定成功后调用 Log.e("MainActivity", "onServiceConnected..."); mService = new Messenger(service); } @Override public void onServiceDisconnected(ComponentName name) { Log.e("MainActivity", "onServiceDisconnected..."); } };
在onServiceConnected中我们实例化了一个Messenger,并且传递了一个IBinder对象,这个IBinder对象就是一直说的Binder驱动。我们进入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); }
是不是又很熟悉?这不就是我们在 基于aidl实现的进程通信 中onSeviceConnect方法实现的一样么?
综上分析客户端和服务端的源代码,其实和我们写aidl完全一样,没有任何区别,Messenger底层其实就是基于aidl来实现的进程通信,只是Android内部已经给我们写好了一个IMessnger.aidl文件,不需要我们手动实现了。
到此,我们就已经分析完了源码了,如果还是不明白的同学建议去翻看下Messenger的源码,并不复杂,到此Android中实现进程通信的常用方式已经介绍完了。
代码传送门 : http:github.com/wms1993/blog_aidl_demo
- Android进程间通信(3)-Messenger实现
- Android使用Messenger实现进程间通信
- Android Messenger 进程间通信
- Android 进程间通信 Messenger
- 使用Messenger实现进程间通信
- Android进程间通信(三):使用Messenger实现进程间通信
- android进程间通信之Messenger
- Android进程间通信之Messenger
- Android进程间通信(一):Messenger
- Android 进程间通信-Intent、Messenger、AIDL
- Android进程间通信之使用Messenger
- Android进程间通信之Messenger浅析
- Android进程间通信之使用Messenger
- Android进程间通信(IPC)之Messenger
- 初识Android进程间通信之---Messenger
- android 进程间通信值Messenger
- Android进程间通信之Messenger
- android-----IPC进程间通信之Messenger
- 利用SortedMap对HashMap进行排序
- PHP几种常用算法
- html中title标签换行的方法整理
- keras环境搭建
- 【C#/WPF】调节图像的HSL(色相、饱和度、明亮度)
- Android进程间通信(3)-Messenger实现
- android 重启,或起不来分析
- 图的强连通分解——Tarjan算法
- 一步一步学MySQL---18 MySQL常用函数(4)
- Java中自定义异常
- 关于blender导出urho3d场景的问题
- mysql中文乱码总结
- org.springframework.beans.factory.BeanCreationException: Error creating bean with name
- Oracle之导入导出