从Service中理解进程间通信Messenger / AIDL(上)代码套路
来源:互联网 发布:mysql yum 安装 编辑:程序博客网 时间:2024/06/04 17:42
转载请注意:http://blog.csdn.net/wjzj000/article/details/77931540
本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅…
https://github.com/zhiaixinyang/PersonalCollect (拆解GitHub上的优秀框架于一体,全部拆离不含任何额外的库导入)
https://github.com/zhiaixinyang/MyFirstApp(Retrofit+RxJava+MVP)
写在前面
今天在看公司项目的时候,发现了一个有意思的效果。app中有一个锁屏的效果,杀死app后,锁屏仍然存在,说明锁屏运行在另一个进程中。
然后厚颜无耻的占用了安卓组boss的工作的时间,让他给讲了一下进程间通讯的原理。boss很有人类灵魂工程师的天赋,了解到我没涉及到c层的东西,所以并没有深到c层,而是在应用层,展开了一顿灵魂深处的缝缝补补…
那么这篇博客存在的意义就是在boss讲授的基础上增加自己的理解并记录下来。
开始
Messenger进程间通讯
我们先看一段官方文档对Messenger介绍:
如需让接口跨不同的进程工作,则可使用 Messenger 为服务创建接口。服务可以这种方式定义对应于不同类型 Message 对象的 Handler。此 Handler 是 Messenger 的基础,后者随后可与客户端分享一个 IBinder,从而让客户端能利用 Message 对象向服务发送命令。此外,客户端还可定义自有 Messenger,以便服务回传消息。
这是执行进程间通信 (IPC) 的最简单方法,因为 Messenger 会在单一线程中创建包含所有请求的队列,这样您就不必对服务进行线程安全设计。
https://developer.android.google.cn/guide/components/bound-services.html
简单叙述一下效果:就是Activity的进程向另一个进程的Service传递一个自定义的类,类内部包含一个x,一个y,由另一个进程的Service计算完毕后回传给我们的Activity。
官方文档是Activity给远端的Service发送消息,这里稍作修改,变成Service给Activity发送消息:
双向互通的思路很简单:既然Activity向Service通信是通过Service回调过来的Messenger,那么我们就在Activity中得到Service的Messenger时,通过这个Messenger把在Activity端生成的Messenger,send过去。这样Service就可以通过Activity的Messenger向我们的Activity发送消息了。
Tips:
Messenger使用Message进行传递消息,Message如果涉及到跨进程,那么携带的数据必须得失Parcelable类型的,因此Serializable是不行的(Can’t marshal non-Parcelable objects across processes.)。
所以String就不能以直接使用Message进行跨进程。这里我们可以使用Bundle做数据传递。
public class RemoteService extends Service { static final int ACTIVITY_MESSENGER = 1; static final String SEND_CONTENT = "send_content"; private Messenger activityMessenger; //构建Messenger,并用来响应绑定组件发送的消息。 class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case ACTIVITY_MESSENGER: if (activityMessenger==null){ //得到绑定组件发过来的它的Messenger,有了这个Messenger,服务就可以向绑定组件发送消息了。 activityMessenger= msg.replyTo; Message message=Message.obtain(); message.what=1; //此处仅仅发送一个String,但是String不是Parcelable对象,不能使用Message进行跨进程,所以这里用Bundle进行处理。 Bundle bundle=new Bundle(); bundle.putString(SEND_CONTENT,"我是来自服务进程的..."); message.setData(bundle); try { activityMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } } break; default: super.handleMessage(msg); } } } //声明一个自己的Messenger,用于给绑定服务的组件发送消息。 final Messenger mMessenger = new Messenger(new IncomingHandler()); @Override public IBinder onBind(Intent intent) { //回调ServiceConnection,让绑定服务的组件得到Messenger对象 return mMessenger.getBinder(); }}
//用于构建组件的Messenger,并响应服务发送过来的消息private Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what==1){ tvShow.setText(msg.getData().getString(RemoteService.SEND_CONTENT)); } } }; private Messenger messenger; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvShow= (TextView) findViewById(R.id.tv_show); tvShow.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //构建自己的Messenger对象,通过Service回调过来的Messenger把自己的Messenger发送给Service,使Service拥有给自己发送消息的能力。 Messenger activityMessenger=new Messenger(handler); Message message=Message.obtain(); message.what=RemoteService.ACTIVITY_MESSENGER; message.replyTo=activityMessenger; try { messenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } } }); ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { //获取Service端的Messenger对象 messenger = new Messenger(iBinder); } @Override public void onServiceDisconnected(ComponentName componentName) { messenger = null; } }; Intent toSerivce = new Intent(this, RemoteService.class); bindService(toSerivce,conn, Context.BIND_AUTO_CREATE); }
接下来让我们看一看AIDL方式的进程通讯。
AIDL进程间通讯
简单叙述一下效果:就是Activity的进程向另一个进程的Service传递一个自定义的类,类内部包含一个x,一个y,由另一个进程的Service计算完毕后回传给我们的Activity。
首先我们先new一个AIDL文件:

有几个tips:
1、要注意包名问题,需要保持和主项目一直,因此为了不出问题,我们还是使用系统的new AIDL的方式,交给系统去处理吧。
2、如果我们需要用到非基础类型,也就是一些类的时候,我们同样要声明同名的AIDL文件,并且不是使用inteface,而是parcelable(下文会有举例)。这里有个先后顺序的问题:如果先声明了class,那么声明AIDL的时候系统会提示换个名字。解决方法:1、先声明AIDL,在声明class。2、随便给AIDL起个名字,然后再改成class的同名。
生成的第一个AIDL文件:
package com.yang.myapplication;//这个就是我们使用的对应class的AIDL,虽然是同一个包下,但也要导入!!import com.yang.myapplication.RemoteBean;interface IMyAdd { //注意这里的in,没有的话无法编译通过。 int add(in RemoteBean bean);}
第二个AIDL,也就是我们的同名class的AIDL:
package com.yang.myapplication;parcelable RemoteBean;
然后是我们的class的RemoteBean,因为涉及到进程间通讯,所以我们要对这个类进行序列化:Parcelable(Android特有的序列化方式,性能好,相对实现比较复杂,但是也无所谓的,AS会提示自动都生成) / Serializable(Java):
public class RemoteBean implements Parcelable{ public int x; public int y; public RemoteBean(){ } protected RemoteBean(Parcel in) { x = in.readInt(); y = in.readInt(); } public static final Creator<RemoteBean> CREATOR = new Creator<RemoteBean>() { @Override public RemoteBean createFromParcel(Parcel in) { return new RemoteBean(in); } @Override public RemoteBean[] newArray(int size) { return new RemoteBean[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeInt(x); parcel.writeInt(y); }}
定义一个Service:
注册Service设置另一个进程运行:
<service android:name=".RemoteService" android:process=":remote"/>
public class RemoteService extends Service { private IBinder iBinder = new MyAddStub(); @Nullable @Override public IBinder onBind(Intent intent) { //返回我们的Stub对象 return iBinder; } //注意这里我们继承了AIDL文件编译后生成的同名class对象的一个内部类Stub(具体作用会在详解时展开) private static final class MyAddStub extends IMyAdd.Stub { @Override public int add(RemoteBean bean) throws RemoteException { return bean.x + bean.y; } }}
Activity中使用:
这里随便给一个View设置一个监听事件:
tvShow.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { RemoteBean bean=new RemoteBean(); bean.x=11; bean.y=11; tvShow.setText("远端进程提供的服务:"+iMyAdd.add(bean)); } catch (RemoteException e) { e.printStackTrace(); } } }); ServiceConnection conn=new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { //注意!这里是进程间通讯和非进程间通讯的区别 iMyAdd = IMyAdd.Stub.asInterface(iBinder); } @Override public void onServiceDisconnected(ComponentName componentName) { iMyAdd=null; } }; Intent toSerivce = new Intent(this, RemoteService.class); bindService(toSerivce,conn, Context.BIND_AUTO_CREATE);
到这里,我们这个进程间通讯的代码套路就完成了。接下来的部分,就开始分析进程间通讯的原理。但是由于篇幅过长,解析篇的内容将在下部分中展开。
尾声
最后希望各位看官可以star我的GitHub,三叩九拜,满地打滚求star:
https://github.com/zhiaixinyang/PersonalCollect
https://github.com/zhiaixinyang/MyFirstApp##
- 从Service中理解进程间通信Messenger / AIDL(上)代码套路
- 关于android进程间通信(handler、messenger、AIDL)
- Android 进程间通信-Intent、Messenger、AIDL
- Android进程间通信:Messenger,AIDL
- Service进程间通信AIDL
- 69 Android service 进程间通信 Messenger(一)
- 70 Android service 进程间通信 Messenger(二)
- Android:Service进程间相互通信: Messenger(系列4)
- android 进程间通信使用aidl和Messenger类
- Android进程间通信AIDL、Binder、Messenger使用哪个?
- 总结关于Service进程通信和跨进程通信的几种方式,AIDL,Messenger,Binder。
- Android进程间(IPC机制)通信(Bundler,Messenger,AIDL,ContentProvider)
- Service详解(六):进程间通信-AIDL
- Android 进程间通信之AIDL service
- 【远程Service】AIDL进程间通信实例
- 进程间通信----Messenger
- 进程间通信 Messenger
- 进程间通信Messenger
- Android中ListView数据使用sAdapter.notifyDataSetChanged();方法不刷新的问题
- php-json
- 德鲁伊连接池
- 20170731题目
- 创建Maven项目时,GroupId和Artifact Id该怎么填写呢?
- 从Service中理解进程间通信Messenger / AIDL(上)代码套路
- 导出java web文件,并在外部运行,发布!
- 计蒜客
- Ruby 10 分钟无废话 Ruby 编程(入门篇)
- Flink入门教程--Data Streaming Fault Tolerance(数据流容错)
- 第一启动项找不到u盘如何是好?
- Python判断文件和字符串编码类型
- 奋斗群群赛8总结与心得,附上周所有错误小结
- 此时此刻此心情