版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Android进程间通讯AIDL使用及问题详解之前对AIDL用的不是很多,今天抽时间对其做一下详细的了解,下面本人主要从以下几个方面对AIDL做一下总结:1. 什么是AIDL?2. 为什么Android中要有AIDL?3. 什么时候使用AIDL?4. 具体怎么实现AIDL?下面我们就进入今天的分析,分析代码Demo会在最后附上下载地址。本文对应博客地址:1 那么首先什么是AIDL呢?AIDL全称为Android Interface definition language,顾名思义它是一种Android内部进程通信接口的描述语言,他妈怎么这么绕啊,简单的说它就是Android进程(现在可以先知道
2、每一个App就是一个单独的进程【一个App也可以定义不同的进程】)间通信的桥梁,通过它我们可以定义进程间的通信接口(通过它我们可以在进程间进行相互操作)。2 为什么Android中要有AIDL呢?因为Android中进程与进程之间是不能相互访问的,每一个进程只能访问自己进程内的数据及操作,每一个进程都有自己的Dalvik VM实例,都有自己的一块独立的内存,都在自己的内存上存储自己的数据,执行自己的操作,相互之间不能通信。3 什么时候使用AIDL?Android官方文档介绍AIDL中有这么一句话:【Note: Using AIDL is necessary only if you allow
3、clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need
4、to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.】只有当你允许来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL,其他情况下你都可以选择其他方法,如使用Messager,也能跨进程通讯。可见AIDL是处理多线程、多客户端并发访问的。而Messager是单线程处理。4 怎么实现AIDL?下面AIDL我们分成两步:1. S
5、erver端代码编写,及为我们提供服务的一端,比如我们有好几个App,有一个App中有一个超牛逼的算法,我们另外几个App中也要用这个算法,这个Server端就是提供算法的那个App。2. 编写Client端代码,Client端为其他几个App。1. 下面我们看一下第一步:server端代码编写。我们以客户端将两个int值传递给服务端,服务端进行相加后返回为例:AS中新建一个项目,创建过程跟普通项目没有区别。然后创建我们的*.aidl文件,在我们新建项目的app文件路径上右键new-AIDL-AIDL File,如下图:创建成功的话会在项目中新增如下目录结构:可以看见与java同级出现了一个a
6、idl目录,其下边的包路径与java包路径相同,再看我们新创建的.aidl文件内容,默认会有一个void basicTypes()方法,其中参数为aidl支持的几种传参基本数据类型(Aidl默认支持的类型包话java基本类型(int、long、boolean等)和(String、List、Map、CharSequence),如果要传递自定义类型,首先要让自定义类型支持parcelable协议),然后我们可以删掉默认方法,添加我们自己的方法,如下:然后Build-rebuild project,在之前eclipse中会自动生成.java文件,AS不行,我们必须重新编译一下项目,然后会在如下文件目
7、录结构中出现我们梦寐以求的.java文件。其代码如下:/* * This file is auto-generated. DO NOT MODIFY. * Original file: D:lylsoftandroidandroidstudiomydemoAidlClientappsrcmainaidlcomjasonaidlaidldemoIMyAidlInterface.aidl */package com.jason.aidl.aidldemo;/ Declare any non-default types here with import statementspublic interf
8、ace IMyAidlInterface extends android.os.IInterface/* Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements com.jason.aidl.aidldemo.IMyAidlInterfaceprivate static final java.lang.String DESCRIPTOR = com.jason.aidl.aidldemo.IMyAidlInterface;
9、/* Construct the stub at attach it to the interface. */public Stub()this.attachInterface(this, DESCRIPTOR);/* * Cast an IBinder object into an com.jason.aidl.aidldemo.IMyAidlInterface interface, * generating a proxy if needed. */public static com.jason.aidl.aidldemo.IMyAidlInterface asInterface(andr
10、oid.os.IBinder obj)if (obj=null) return null;android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (iin!=null)&(iin instanceof com.jason.aidl.aidldemo.IMyAidlInterface) return (com.jason.aidl.aidldemo.IMyAidlInterface)iin);return new com.jason.aidl.aidldemo.IMyAidlInterface.Stub.Proxy(o
11、bj);Override public android.os.IBinder asBinder()return this;Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteExceptionswitch (code)case INTERFACE_TRANSACTION:reply.writeString(DESCRIPTOR);return true;case TRANSACTION_ad
12、d:data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();int _arg1;_arg1 = data.readInt();int _result = this.add(_arg0, _arg1);reply.writeNoException();reply.writeInt(_result);return true;return super.onTransact(code, data, reply, flags);private static class Proxy implements com.jason.ai
13、dl.aidldemo.IMyAidlInterfaceprivate android.os.IBinder mRemote;Proxy(android.os.IBinder remote)mRemote = remote;Override public android.os.IBinder asBinder()return mRemote;public java.lang.String getInterfaceDescriptor()return DESCRIPTOR;Override public int add(int a, int b) throws android.os.Remote
14、Exceptionandroid.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();int _result;try _data.writeInterfaceToken(DESCRIPTOR);_data.writeInt(a);_data.writeInt(b);mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);_reply.readException();_result = _rep
15、ly.readInt();finally _reply.recycle();_data.recycle();return _result;static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);public int add(int a, int b) throws android.os.RemoteException;可以看到,在我们编译的出的.java文件中有一个Stub内部类,我们在MainActivity同目录下创建一个Service,创建一个Stub类实现add()方法后在on
16、Bind()方法中返回,代码如下:package com.jason.aidl.aidldemo;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import com.jason.aidl.aidldemo.Person;public class MyAidlService extends Service Override public int onStartCo
17、mmand(Intent intent, int flags, int startId) Log.i(Log_LYL, Onstart); return super.onStartCommand(intent, flags, startId); Override public IBinder onBind(Intent intent) return stub; IMyAidlInterface.Stub stub = new IMyAidlInterface.Stub() Override public int add(int a, int b) throws RemoteException
18、return a + b; ;到这里我们的Server端代码就完成了?没有,我们要知道,我们其他项目中没有这个Service,所以我们要想在其他App中打开这个service必须通过隐式意图,所以我们必须在我们的Manifest.xml中添加一个action,如下: 到这里服务端工作算是基本完成了。2.下面看第二步编写Client端代码。新建一个Client端项目,我们将服务端整个aidl下的文件统统考本到Client端与java同级目录下,如下图:编译项目后会在Client端也生成一个.java文件,且与Server端生成的.java文件一模一样,然后我们就可以在我们的activity_ma
19、in.xml中布局,然后在MainAcitivity中进行绑定service进行远程调用运算了,xml代码与activity代码如下: package com.jason.aidl.client.aidlclient;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.content.pm.PackageManager;import andr
20、oid.content.pm.ResolveInfo;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.EditText;import android.widget.TextView;import com.jason.aidl.aidldemo.IMyAidlInterface;impor
21、t java.util.List;public class MainActivity extends AppCompatActivity private EditText et_num1, et_num2; private TextView tv; private IMyAidlInterface mService; Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_n
22、um1 = (EditText) findViewById(R.id.et_num1); et_num2 = (EditText) findViewById(R.id.et_num2); tv = (TextView) findViewById(R.id.tv); Intent intent = new Intent(); intent.setAction(com.lyl.aidl); Intent intent1 = new Intent(createExplicitFromImplicitIntent(this, intent); bindService(intent1, mService
23、C, Context.BIND_AUTO_CREATE); public void add(View v) int a = Integer.valueOf(et_num1.getText().toString(); int b = Integer.valueOf(et_num2.getText().toString(); try int res = mService.add(a, b); tv.setText(res+); catch (RemoteException e) e.printStackTrace(); ServiceConnection mServiceC = new Servi
24、ceConnection() Override public void onServiceConnected(ComponentName name, IBinder service) mService = IMyAidlInterface.Stub.asInterface(service); Override public void onServiceDisconnected(ComponentName name) ; /* * 兼容Android5.0中service的intent一定要显性声明 * * param context * param implicitIntent * retur
25、n */ public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) / Retrieve all services that can match the given intent PackageManager pm = context.getPackageManager(); /通过queryIntentActivities()方法,查询Android系统的所有具备ACTION_MAIN和CATEGORY_LAUNCHER /的Intent的应用程序,点击后,能启动
26、该应用,说白了就是做一个类似Home程序的简易Launcher 。 List resolveInfo = pm.queryIntentServices(implicitIntent, 0); / Make sure only one match was found if (resolveInfo = null | resolveInfo.size() != 1) return null; / Get component info and create ComponentName ResolveInfo serviceInfo = resolveInfo.get(0); String packa
27、geName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceI; ComponentName component = new ComponentName(packageName, className); / Create a new intent. Use the old one for extras and such reuse Intent explicitIntent = new Intent(implicitIntent); / Set the component
28、 to be explicit explicitIntent.setComponent(component); return explicitIntent; 这里用到了createExplicitFromImplicitIntent()方法是因为Android5.0中service的intent一定要显性声明,否则会报如下错误:01-10 19:17:43.733 14662-14662/com.jason.aidl.client.aidlclient E/AndroidRuntime: FATAL EXCEPTION: mainProcess: com.jason.aidl.client.a
29、idlclient, PID: 14662java.lang.RuntimeException: Unable to start activity ComponentInfocom.jason.aidl.client.aidlclient/com.jason.aidl.client.aidlclient.MainActivity: java.lang.IllegalArgumentException: Service Intent must be explicit: Intent act=com.lyl.aidl at android.app.ActivityThread.performLau
30、nchActivity(ActivityThread.java:2381) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2443) at android.app.ActivityThread.access$800(ActivityThread.java:157) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) at android.os.Handler.dispatchMessage(Handler.j
31、ava:102) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5344) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at ernal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908) at
32、 ernal.os.ZygoteInit.main(ZygoteInit.java:703) Caused by: java.lang.IllegalArgumentException: Service Intent must be explicit: Intent act=com.lyl.aidl at android.app.ContextImpl.validateServiceIntent(ContextImpl.java:1781) at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:
33、1880) at android.app.ContextImpl.bindService(ContextImpl.java:1858) at android.content.ContextWrapper.bindService(ContextWrapper.java:539) at com.jason.aidl.client.aidlclient.MainActivity.onCreate(MainActivity.java:37) at android.app.Activity.performCreate(Activity.java:6033) at android.app.Instrume
34、ntation.callActivityOnCreate(Instrumentation.java:1106) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2334) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2443) at android.app.ActivityThread.access$800(ActivityThread.java:157) at android.app.Activity
35、Thread$H.handleMessage(ActivityThread.java:1344) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5344) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method
36、.java:372) at ernal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908) at ernal.os.ZygoteInit.main(ZygoteInit.java:703)运行我们的Server端及Client端,在Client端的两个editText中输入两个数字点击按钮运行结果如下:看见运行结果与我们预期一样,可见我们通过AIDL实现了App与App之间的远程调用。以上只是一个简单的基本数据类型操作,那么我们怎么通过AIDL进行对象的操作呢,我们在之
37、前代码上做些修改就行了,看下边吧。我们在Server端与我们创建的.aidl同目录下创建一个Person.java的类与Person.aidl文件,目录结构如下:Person.java中成员变量包括一个name,一个age,ctrl+insert添加set与get方法,然后实现Parcelable接口序列化,里边有些方法需要自己实现Creator啊writeToParcel啊什么的,自己弄一下就行,两次ctrl+enter就行,然后自己写一个readFromParcel(Parcel dest)方法,要保证赋值顺序与writeToParcel中一致,否则会出问题。具体可以看下边代码:packa
38、ge com.jason.aidl.aidldemo;import android.os.Parcel;import android.os.Parcelable;public class Person implements Parcelable private String name; private int age; public Person() protected Person(Parcel in) name = in.readString(); age = in.readInt(); public static final Creator CREATOR = new Creator()
39、 Override public Person createFromParcel(Parcel in) return new Person(in); Override public Person newArray(int size) return new Personsize; ; public String getName() return name; public void setName(String name) = name; public int getAge() return age; public void setAge(int age) this.age =
40、 age; Override public int describeContents() return 0; Override public void writeToParcel(Parcel dest, int flags) dest.writeString(name); dest.writeInt(age); public void readFromParcel(Parcel dest) name = dest.readString(); age = dest.readInt(); Override public String toString() return Person + name= + name + + , age= + age + ; Person.java完成了,看一下Person.aidl文件代码,很简单,如下:/ Person.aidl.aidlpackage com.jason.aidl.aidldemo;/ Declare any non-default types here with import statementsparcelable Pers
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 销售责任制度
- 镇街消防安全责任制度
- 防汛责任制度
- 防疫五方责任制度
- 陪餐试餐责任制度
- 露天矿环保责任制度
- 食品安全管理人责任制度
- 食堂工作责任制度
- 餐厅垃圾房责任制度
- 餐饮店安全生产责任制度
- 慢性病健康管理规范
- 检验检测机构质量手册程序文件质量记录合集(依据2023年版评审准则)
- 护理伦理学(高职)PPT完整全套教学课件
- 牛羊布病流行病学调查表
- 国际贸易理论与实务习题答案汇总(王峰第三版)第1-16章+实务案例题
- 《十万个为什么》导读课
- 教育管理干部理论测试题附答案
- GB/T 5237.1-2017铝合金建筑型材第1部分:基材
- GB/T 26121-2010可曲挠橡胶接头
- FZ/T 50046-2019高模量纤维单纤维拉伸性能试验方法
- 血液透析室医院感染紧急情况应急预案及处理流程
评论
0/150
提交评论