首页 文章 精选 留言 我的

精选列表

搜索[message],共6323篇文章
优秀的个人博客,低调大师

Android——进程通信/ AIDL/Message相关知识总结贴

Android 多进程通信 http://www.apkbus.com/android-83462-1-1.html Android 跨进程通信(一) http://www.apkbus.com/android-2393-1-1.html Android 跨进程通信(二) http://www.apkbus.com/android-2394-1-1.html Android 中 AIDL 实现(跨进程通信) http://www.apkbus.com/android-15211-1-1.html Android 进程间通信 http://www.apkbus.com/android-91355-1-1.html Android 系统进程间通信 Binder 机制 http://www.apkbus.com/android-112500-1-1.html 使用AIDL实现进程间的通信 http://www.apkbus.com/android-114839-1-1.html Android进程间通信(IPC)机制Binder简要介绍和学习计划 http://www.apkbus.com/android-99739-1-1.html 服务组件的进程间通信模型 http://www.apkbus.com/android-83850-1-1.html 使用AIDL实现进程间的通信之复杂类型传递 http://www.apkbus.com/android-114840-1-1.html 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client http://www.apkbus.com/android-99743-1-1.html android 组件间的交互和进程间 IPC 通信 http://www.apkbus.com/android-20707-1-1.html Android 之 Binder与进程间通信 http://www.apkbus.com/android-43314-1-1.html Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析 http://www.apkbus.com/android-99747-1-1.html Android进程间通信--消息机制及IPC机制实现 http://www.apkbus.com/android-3944-1-1.html 本文转自qianqianlianmeng博客园博客,原文链接:http://www.cnblogs.com/aimeng/p/3298609.html ,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android 基于Message的进程间通信 Messenger完全解析

1、概述 Binder能干什么?Binder可以提供系统中任何程序都可以访问的全局服务。这个功能当然是任何系统都应该提供的,下面我们简单看一下Android的Binder的框架 Android Binder框架分为服务器接口、Binder驱动、以及客户端接口;简单想一下,需要提供一个全局服务,那么全局服务那端即是服务器接口,任何程序即客户端接口,它们之间通过一个Binder驱动访问。 服务器端接口:实际上是Binder类的对象,该对象一旦创建,内部则会启动一个隐藏线程,会接收Binder驱动发送的消息,收到消息后,会执行Binder对象中的onTransact()函数,并按照该函数的参数执行不同的服务器端代码。 Binder驱动:该对象也为Binder类的实例,客户端通过该对象访问远程服务。 客户端接口:获得Binder驱动,调用其transact()发送消息至服务器 如果大家对上述不了解,没关系,下面会通过例子来更好的说明,实践是检验真理的唯一标准嘛 2、AIDL的使用 如果对Android比较熟悉,那么一定使用过AIDL,如果你还不了解,那么也没关系,下面会使用一个例子展示AIDL的用法。 我们使用AIDL实现一个跨进程的加减法调用 1、服务端 新建一个项目,创建一个包名:com.zhy.calc.aidl,在包内创建一个ICalcAIDL文件: [java] view plain copy packagecom.zhy.calc.aidl; interfaceICalcAIDL { intadd(intx,inty); intmin(intx,inty); } 注意,文件名为ICalcAIDL.aidl 然后在项目的gen目录下会生成一个ICalcAIDL.Java文件,暂时不贴这个文件的代码了,后面会详细说明 然后我们在项目中新建一个Service,代码如下: [java] view plain copy packagecom.example.zhy_binder; importcom.zhy.calc.aidl.ICalcAIDL; importandroid.app.Service; importandroid.content.Intent; importandroid.os.IBinder; importandroid.os.RemoteException; importandroid.util.Log; publicclassCalcServiceextendsService { privatestaticfinalStringTAG="server"; publicvoidonCreate() { Log.e(TAG,"onCreate"); } publicIBinderonBind(Intentt) { Log.e(TAG,"onBind"); returnmBinder; } publicvoidonDestroy() { Log.e(TAG,"onDestroy"); super.onDestroy(); } publicbooleanonUnbind(Intentintent) { Log.e(TAG,"onUnbind"); returnsuper.onUnbind(intent); } publicvoidonRebind(Intentintent) { Log.e(TAG,"onRebind"); super.onRebind(intent); } privatefinalICalcAIDL.StubmBinder=newICalcAIDL.Stub() { @Override publicintadd(intx,inty)throwsRemoteException { returnx+y; } @Override publicintmin(intx,inty)throwsRemoteException { returnx-y; } }; } 在此Service中,使用生成的ICalcAIDL创建了一个mBinder的对象,并在Service的onBind方法中返回 最后记得在AndroidManifest中注册 [html] view plain copy <serviceandroid:name="com.example.zhy_binder.CalcService"> <intent-filter> <actionandroid:name="com.zhy.aidl.calc"/> <categoryandroid:name="android.intent.category.DEFAULT"/> </intent-filter> </service> 这里我们指定了一个name,因为我们一会会在别的应用程序中通过Intent来查找此Service;这个不需要Activity,所以我也就没写Activity,安装完成也看不到安装图标,悄悄在后台运行着。 到此,服务端编写完毕。下面开始编写客户端 2、客户端 客户端的代码比较简单,创建一个布局,里面包含4个按钮,分别为绑定服务,解除绑定,调用加法,调用减法 布局文件: [html] view plain copy <LinearLayoutxmlns: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:orientation="vertical"> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="bindService" android:text="BindService"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="unbindService" android:text="UnbindService"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="addInvoked" android:text="12+12"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="minInvoked" android:text="50-12"/> </LinearLayout> 主Activity [java] view plain copy packagecom.example.zhy_binder_client; importandroid.app.Activity; importandroid.content.ComponentName; importandroid.content.Context; importandroid.content.Intent; importandroid.content.ServiceConnection; importandroid.os.Bundle; importandroid.os.IBinder; importandroid.util.Log; importandroid.view.View; importandroid.widget.Toast; importcom.zhy.calc.aidl.ICalcAIDL; publicclassMainActivityextendsActivity { privateICalcAIDLmCalcAidl; privateServiceConnectionmServiceConn=newServiceConnection() { @Override publicvoidonServiceDisconnected(ComponentNamename) { Log.e("client","onServiceDisconnected"); mCalcAidl=null; } @Override publicvoidonServiceConnected(ComponentNamename,IBinderservice) { Log.e("client","onServiceConnected"); mCalcAidl=ICalcAIDL.Stub.asInterface(service); } }; @Override protectedvoidonCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } /** *点击BindService按钮时调用 *@paramview */ publicvoidbindService(Viewview) { Intentintent=newIntent(); intent.setAction("com.zhy.aidl.calc"); bindService(intent,mServiceConn,Context.BIND_AUTO_CREATE); } /** *点击unBindService按钮时调用 *@paramview */ publicvoidunbindService(Viewview) { unbindService(mServiceConn); } /** *点击12+12按钮时调用 *@paramview */ publicvoidaddInvoked(Viewview)throwsException { if(mCalcAidl!=null) { intaddRes=mCalcAidl.add(12,12); Toast.makeText(this,addRes+"",Toast.LENGTH_SHORT).show(); }else { Toast.makeText(this,"服务器被异常杀死,请重新绑定服务端",Toast.LENGTH_SHORT) .show(); } } /** *点击50-12按钮时调用 *@paramview */ publicvoidminInvoked(Viewview)throwsException { if(mCalcAidl!=null) { intaddRes=mCalcAidl.min(58,12); Toast.makeText(this,addRes+"",Toast.LENGTH_SHORT).show(); }else { Toast.makeText(this,"服务端未绑定或被异常杀死,请重新绑定服务端",Toast.LENGTH_SHORT) .show(); } } } 很标准的绑定服务的代码。 直接看运行结果: 我们首先点击BindService按钮,查看log [html] view plain copy 08-0922:56:38.959:E/server(29692):onCreate 08-0922:56:38.959:E/server(29692):onBind 08-0922:56:38.959:E/client(29477):onServiceConnected 可以看到,点击BindService之后,服务端执行了onCreate和onBind的方法,并且客户端执行了onServiceConnected方法,标明服务器与客户端已经联通 然后点击12+12,50-12可以成功的调用服务端的代码并返回正确的结果 下面我们再点击unBindService [html] view plain copy 08-0922:59:25.567:E/server(29692):onUnbind 08-0922:59:25.567:E/server(29692):onDestroy 由于我们当前只有一个客户端绑定了此Service,所以Service调用了onUnbind和onDestory 然后我们继续点击12+12,50-12,通过上图可以看到,依然可以正确执行,也就是说即使onUnbind被调用,连接也是不会断开的,那么什么时候会端口呢? 即当服务端被异常终止的时候,比如我们现在在手机的正在执行的程序中找到该服务: 点击停止,此时查看log [html] view plain copy 08-0923:04:21.433:E/client(30146):onServiceDisconnected 可以看到调用了onServiceDisconnected方法,此时连接被断开,现在点击12+12,50-12的按钮,则会弹出Toast服务端断开的提示。 说了这么多,似乎和Binder框架没什么关系,下面我们来具体看一看AIDL为什么做了些什么。 3、分析AIDL生成的代码 1、服务端 先看服务端的代码,可以看到我们服务端提供的服务是由 [java] view plain copy privatefinalICalcAIDL.StubmBinder=newICalcAIDL.Stub() { @Override publicintadd(intx,inty)throwsRemoteException { returnx+y; } @Override publicintmin(intx,inty)throwsRemoteException { returnx-y; } }; ICalcAILD.Stub来执行的,让我们来看看Stub这个类的声明: [java] view plain copy publicstaticabstractclassStubextendsandroid.os.Binderimplementscom.zhy.calc.aidl.ICalcAIDL 清楚的看到这个类是Binder的子类,是不是符合我们文章开通所说的服务端其实是一个Binder类的实例 接下来看它的onTransact()方法: [java] view plain copy @OverridepublicbooleanonTransact(intcode,android.os.Parceldata,android.os.Parcelreply,intflags)throwsandroid.os.RemoteException { switch(code) { caseINTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); returntrue; } caseTRANSACTION_add: { data.enforceInterface(DESCRIPTOR); int_arg0; _arg0=data.readInt(); int_arg1; _arg1=data.readInt(); int_result=this.add(_arg0,_arg1); reply.writeNoException(); reply.writeInt(_result); returntrue; } caseTRANSACTION_min: { data.enforceInterface(DESCRIPTOR); int_arg0; _arg0=data.readInt(); int_arg1; _arg1=data.readInt(); int_result=this.min(_arg0,_arg1); reply.writeNoException(); reply.writeInt(_result); returntrue; } } returnsuper.onTransact(code,data,reply,flags); } 文章开头也说到服务端的Binder实例会根据客户端依靠Binder驱动发来的消息,执行onTransact方法,然后由其参数决定执行服务端的代码。 可以看到onTransact有四个参数 code , data ,replay , flags code 是一个整形的唯一标识,用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法 data客户端传递过来的参数 replay服务器返回回去的值 flags标明是否有返回值,0为有(双向),1为没有(单向) 我们仔细看caseTRANSACTION_min中的代码 data.enforceInterface(DESCRIPTOR);与客户端的writeInterfaceToken对用,标识远程服务的名称 int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); 接下来分别读取了客户端传入的两个参数 int _result = this.min(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); 然后执行this.min,即我们实现的min方法;返回result由reply写回。 add同理,可以看到服务端通过AIDL生成Stub的类,封装了服务端本来需要写的代码。 2、客户端 客户端主要通过ServiceConnected与服务端连接 [java] view plain copy privateServiceConnectionmServiceConn=newServiceConnection() { @Override publicvoidonServiceDisconnected(ComponentNamename) { Log.e("client","onServiceDisconnected"); mCalcAidl=null; } @Override publicvoidonServiceConnected(ComponentNamename,IBinderservice) { Log.e("client","onServiceConnected"); mCalcAidl=ICalcAIDL.Stub.asInterface(service); } }; 如果你比较敏锐,应该会猜到这个onServiceConnected中的IBinder实例,其实就是我们文章开通所说的Binder驱动,也是一个Binder实例 在ICalcAIDL.Stub.asInterface中最终调用了: [java] view plain copy returnnewcom.zhy.calc.aidl.ICalcAIDL.Stub.Proxy(obj); 这个Proxy实例传入了我们的Binder驱动,并且封装了我们调用服务端的代码,文章开头说,客户端会通过Binder驱动的transact()方法调用服务端代码 直接看Proxy中的add方法 [java] view plain copy @Overridepublicintadd(intx,inty)throwsandroid.os.RemoteException { android.os.Parcel_data=android.os.Parcel.obtain(); android.os.Parcel_reply=android.os.Parcel.obtain(); int_result; try{ _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(x); _data.writeInt(y); mRemote.transact(Stub.TRANSACTION_add,_data,_reply,0); _reply.readException(); _result=_reply.readInt(); } finally{ _reply.recycle(); _data.recycle(); } return_result; } 首先声明两个Parcel对象,一个用于传递数据,一个用户接收返回的数据 _data.writeInterfaceToken(DESCRIPTOR);与服务器端的enforceInterfac对应 _data.writeInt(x); _data.writeInt(y);写入需要传递的参数 mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); 终于看到了我们的transact方法,第一个对应服务端的code,_data,_repay分别对应服务端的data,reply,0表示是双向的 _reply.readException(); _result = _reply.readInt(); 最后读出我们服务端返回的数据,然后return。可以看到和服务端的onTransact基本是一行一行对应的。 到此,我们已经通过AIDL生成的代码解释了Android Binder框架的工作原理。Service的作用其实就是为我们创建Binder驱动,即服务端与客户端连接的桥梁。 AIDL其实通过我们写的aidl文件,帮助我们生成了一个接口,一个Stub类用于服务端,一个Proxy类用于客户端调用。那么我们是否可以不通过写AIDL来实现远程的通信呢?下面向大家展示如何完全不依赖AIDL来实现客户端与服务端的通信。 4、不依赖AIDL实现程序间通讯 1、服务端代码 我们新建一个CalcPlusService.java用于实现两个数的乘和除 [java] view plain copy packagecom.example.zhy_binder; importandroid.app.Service; importandroid.content.Intent; importandroid.os.Binder; importandroid.os.IBinder; importandroid.os.Parcel; importandroid.os.RemoteException; importandroid.util.Log; publicclassCalcPlusServiceextendsService { privatestaticfinalStringDESCRIPTOR="CalcPlusService"; privatestaticfinalStringTAG="CalcPlusService"; publicvoidonCreate() { Log.e(TAG,"onCreate"); } @Override publicintonStartCommand(Intentintent,intflags,intstartId) { Log.e(TAG,"onStartCommand"); returnsuper.onStartCommand(intent,flags,startId); } publicIBinderonBind(Intentt) { Log.e(TAG,"onBind"); returnmBinder; } publicvoidonDestroy() { Log.e(TAG,"onDestroy"); super.onDestroy(); } publicbooleanonUnbind(Intentintent) { Log.e(TAG,"onUnbind"); returnsuper.onUnbind(intent); } publicvoidonRebind(Intentintent) { Log.e(TAG,"onRebind"); super.onRebind(intent); } privateMyBindermBinder=newMyBinder(); privateclassMyBinderextendsBinder { @Override protectedbooleanonTransact(intcode,Parceldata,Parcelreply, intflags)throwsRemoteException { switch(code) { case0x110: { data.enforceInterface(DESCRIPTOR); int_arg0; _arg0=data.readInt(); int_arg1; _arg1=data.readInt(); int_result=_arg0*_arg1; reply.writeNoException(); reply.writeInt(_result); returntrue; } case0x111: { data.enforceInterface(DESCRIPTOR); int_arg0; _arg0=data.readInt(); int_arg1; _arg1=data.readInt(); int_result=_arg0/_arg1; reply.writeNoException(); reply.writeInt(_result); returntrue; } } returnsuper.onTransact(code,data,reply,flags); } }; } 我们自己实现服务端,所以我们自定义了一个Binder子类,然后复写了其onTransact方法,我们指定服务的标识为CalcPlusService,然后0x110为乘,0x111为除; 记得在AndroidMenifest中注册 [html] view plain copy <serviceandroid:name="com.example.zhy_binder.CalcPlusService"> <intent-filter> <actionandroid:name="com.zhy.aidl.calcplus"/> <categoryandroid:name="android.intent.category.DEFAULT"/> </intent-filter> </service> 服务端代码结束。 2、客户端代码 单独新建了一个项目,代码和上例很类似 首先布局文件: [html] view plain copy <LinearLayoutxmlns: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:orientation="vertical"> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="bindService" android:text="BindService"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="unbindService" android:text="UnbindService"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="mulInvoked" android:text="50*12"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="divInvoked" android:text="36/12"/> </LinearLayout> 可以看到加入了乘和除 然后是Activity的代码 [java] view plain copy packagecom.example.zhy_binder_client03; importandroid.app.Activity; importandroid.content.ComponentName; importandroid.content.Context; importandroid.content.Intent; importandroid.content.ServiceConnection; importandroid.os.Bundle; importandroid.os.IBinder; importandroid.os.RemoteException; importandroid.util.Log; importandroid.view.View; importandroid.widget.Toast; publicclassMainActivityextendsActivity { privateIBindermPlusBinder; privateServiceConnectionmServiceConnPlus=newServiceConnection() { @Override publicvoidonServiceDisconnected(ComponentNamename) { Log.e("client","mServiceConnPlusonServiceDisconnected"); } @Override publicvoidonServiceConnected(ComponentNamename,IBinderservice) { Log.e("client","mServiceConnPlusonServiceConnected"); mPlusBinder=service; } }; @Override protectedvoidonCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } publicvoidbindService(Viewview) { IntentintentPlus=newIntent(); intentPlus.setAction("com.zhy.aidl.calcplus"); booleanplus=bindService(intentPlus,mServiceConnPlus, Context.BIND_AUTO_CREATE); Log.e("plus",plus+""); } publicvoidunbindService(Viewview) { unbindService(mServiceConnPlus); } publicvoidmulInvoked(Viewview) { if(mPlusBinder==null) { Toast.makeText(this,"未连接服务端或服务端被异常杀死",Toast.LENGTH_SHORT).show(); }else { android.os.Parcel_data=android.os.Parcel.obtain(); android.os.Parcel_reply=android.os.Parcel.obtain(); int_result; try { _data.writeInterfaceToken("CalcPlusService"); _data.writeInt(50); _data.writeInt(12); mPlusBinder.transact(0x110,_data,_reply,0); _reply.readException(); _result=_reply.readInt(); Toast.makeText(this,_result+"",Toast.LENGTH_SHORT).show(); }catch(RemoteExceptione) { e.printStackTrace(); }finally { _reply.recycle(); _data.recycle(); } } } publicvoiddivInvoked(Viewview) { if(mPlusBinder==null) { Toast.makeText(this,"未连接服务端或服务端被异常杀死",Toast.LENGTH_SHORT).show(); }else { android.os.Parcel_data=android.os.Parcel.obtain(); android.os.Parcel_reply=android.os.Parcel.obtain(); int_result; try { _data.writeInterfaceToken("CalcPlusService"); _data.writeInt(36); _data.writeInt(12); mPlusBinder.transact(0x111,_data,_reply,0); _reply.readException(); _result=_reply.readInt(); Toast.makeText(this,_result+"",Toast.LENGTH_SHORT).show(); }catch(RemoteExceptione) { e.printStackTrace(); }finally { _reply.recycle(); _data.recycle(); } } } } 为了明了,我直接在mulInvoked里面写了代码,和服务端都没有抽象出一个接口。首先绑定服务时,通过onServiceConnected得到Binder驱动即mPlusBinder; 然后准备数据,调用transact方法,通过code指定执行服务端哪个方法,代码和上面的分析一致。 下面看运行结果: 是不是很好的实现了我们两个应用程序间的通讯,并没有使用aidl文件,也从侧面分析了我们上述分析是正确的。 好了,就到这里,相信大家看完这篇博文,对aidl和Binder的理解也会更加深刻。 测试代码点击下载 代码先安装server端的代码,然后再安装client端的。。。 本文转自 一点点征服 博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/7307015.html,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册