Android之AIDL知识总结
1.AIDL介绍
AIDL是一个缩写,全称是Android Interface Definition Language,翻译为Android接口定义语言。主要用于线程之间的通信,本文主要以不同应用之间使用AIDL通信为例介绍AIDL。
2.AIDL的使用
AIDL的使用按照AIDL文件类型分类,一种是序列化数据类,需要实现Parcelable,另一种是定义方法接口,以供系统使用来完成跨进程通信的。
AIDL默认支持JAVA的八种基本数据类型、String、CharSequence、List类型、Map类型。
2.1. 数据类实现Parcelable
Message.aidl文件
// Message.aidl
package com.zhangmiao.aidlservice; // Declare any non-default types here with import statements parcelable Message;
Message.java文件
package com.zhangmiao.aidlservice; import android.os.Parcel;
import android.os.Parcelable; /**
* Created by zhangmiao on 2017/4/19.
*/ public class Message implements Parcelable {
protected int status;
protected String content; public int getStatus() {
return status;
} public void setStatus(int status) {
this.status = status;
} public String getContent() {
return content;
} public void setContent(String content) {
this.content = content;
} public Message(int status, String content){
this.status = status;
this.content = content;
} public Message(Parcel parcel){
status = parcel.readInt();
content = parcel.readString();
} public final static Creator<Message> CREATOR = new Creator<Message>() {
@Override
public Message createFromParcel(Parcel source) {
return new Message(source);
} @Override
public Message[] newArray(int size) {
return new Message[size];
}
}; @Override
public int describeContents() {
return 0;
} @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(status);
dest.writeString(content);
} @Override
public String toString() {
return "status : "+status + ",content : "+content;
}
}
2.2.定义方法接口
MessageManager.aidl文件
// MessageManager.aidl
package com.zhangmiao.aidlservice; // Declare any non-default types here with import statements
import com.zhangmiao.aidlservice.Message;
interface MessageManager {
List<Message> getMessages();
void addMessage(in Message message);
}
2.3.移植aidl与java文件
将服务端的Message.aidl、MessageManager.aidl与Message.java文件移植到客户端项目中,注意文件的包名要保持一致,不可不同。下图是项目结构图。
2.4.编写服务器代码
package com.zhangmiao.aidlservice; import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable; import java.util.ArrayList;
import java.util.List; /**
* Created by zhangmiao on 2017/4/19.
*/ public class AIDLService extends Service {
private final static String TAG = AIDLService.class.getSimpleName();
private List<Message> mMessageList = new ArrayList<>();
private final MessageManager.Stub messageService = new MessageManager.Stub() { @Override
public List<Message> getMessages() throws RemoteException {
if(mMessageList != null) {
return mMessageList;
}
return new ArrayList<>();
} @Override
public void addMessage(Message message) throws RemoteException {
if(mMessageList == null){
mMessageList = new ArrayList<>();
}
mMessageList.add(message);
}
}; @Override
public void onCreate() {
super.onCreate();
Message message1 = new Message(1,"open");
mMessageList.add(message1);
Message message2 = new Message(2,"get");
mMessageList.add(message2);
} @Nullable
@Override
public IBinder onBind(Intent intent) {
return messageService;
}
}
修改服务器的AndroidManifest.xml文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.zhangmiao.aidlservice"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".AIDLService"
android:exported="true">
<intent-filter>
<action android:name="com.zhangmiao.service.aidlservice" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
</application> </manifest>
2.5.编写客户端代码
package com.zhangmiao.aidldemo; import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.zhangmiao.aidlservice.Message;
import com.zhangmiao.aidlservice.MessageManager; import java.util.List; public class MainActivity extends AppCompatActivity { private final static String TAG = MainActivity.class.getSimpleName(); @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setPackage("com.zhangmiao.aidlservice");
intent.setAction("com.zhangmiao.service.aidlservice");
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
} private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG,"ServiceConnection onServiceConnected");
MessageManager messageManager = MessageManager.Stub.asInterface(service);
try {
List<Message> messages = messageManager.getMessages();
for(int i = 0;i<messages.size();i++){
Log.d(TAG,"get Message for MessageManager:"+messages.get(i).toString());
}
}catch (RemoteException e){
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG,"ServiceConnection onServiceDisconnected");
}
};
}
运行结果如图:
3.AIDL继承
在AIDL的序列化数据类的时候,有时候数据类有很多,并且是有继承关系的,这个时候直接使用是有问题的,需要处理一下。
3.1.错误做法
3.1.1.添加ConnectMessage类
ConnectMessage.aidl文件
// ConnectMessage.aidl
package com.zhangmiao.aidlservice; // Declare any non-default types here with import statements
parcelable ConnectMessage;
ConnectMessage.java文件
package com.zhangmiao.aidlservice;
import android.os.Parcel;
/**
* Created by zhangmiao on 2017/4/25.
*/
public class ConnectMessage extends Message {
protected int isConnect;
public ConnectMessage(int status,String content,int isConnect){
super(status,content);
this.isConnect = isConnect;
}
public ConnectMessage(Parcel parcel){
super(parcel);
isConnect = parcel.readInt();
}
public final static Creator<ConnectMessage> CREATOR = new Creator<ConnectMessage>() {
@Override
public ConnectMessage createFromParcel(Parcel source) {
return new ConnectMessage(source);
}
@Override
public ConnectMessage[] newArray(int size) {
return new ConnectMessage[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(status);
dest.writeString(content);
dest.writeInt(isConnect);
}
@Override
public String toString() {
return "status : "+status + ",content : "+content+",isConnect : "+isConnect;
}
}
注意:客户端与服务端ConnectMessage的aidl文件与java文件都需要添加。
3.1.2 在服务端发送ConnnectMessage消息。
修改AIDLService类中的onCreate()方法:
@Override
public void onCreate() {
super.onCreate();
Message message1 = new Message(1,"open");
mMessageList.add(message1);
Message message2 = new Message(2,"get");
mMessageList.add(message2);
Message connMessage = new ConnectMessage(3,"conn",1);
mMessageList.add(connMessage);
}
3.1.3.在客户端接收ConnnectMessage消息。
修改客户端的MainActivity的ServiceConnect对象的实现。
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG,"ServiceConnection onServiceConnected");
MessageManager messageManager = MessageManager.Stub.asInterface(service);
try {
List<Message> messages = messageManager.getMessages();
for(int i = 0;i<messages.size();i++){
if(messages.get(i).getStatus() == 3){
ConnectMessage connectMessage = (ConnectMessage)message;
Log.d(TAG,"get conn Message for MessageManager:"+connectMessage.toString());
break;
}
Log.d(TAG,"get Message for MessageManager:"+message.toString());
}
}catch (RemoteException e){
e.printStackTrace();
}
} @Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG,"ServiceConnection onServiceDisconnected");
}
};
这个时候运行就会出现如下错误:
04-26 11:43:20.998 2567-2567/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.zhangmiao.aidldemo, PID: 2567 java.lang.ClassCastException: com.zhangmiao.aidlservice.Message cannot be cast to com.zhangmiao.aidlservice.ConnectMessage
at com.zhangmiao.aidldemo.MainActivity$1.onServiceConnected(MainActivity.java:42)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1101)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1118)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5095)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
at dalvik.system.NativeStart.main(Native Method)
3.2.正确做法
在java中,用子类对象初始化父类,可以将父类强制转换成引用的子类,这样使用是没有问题的,但是在AIDL使用中,在服务器端用子类对象初始化父类,在服务器端将父类强制转换成引用的子类这样是没有问题的,但是在客户端这样强制转换时不可以的,因为客户端只是将父类当做父类,如果还是想要在客户端进行父类强制转换成引用的子类,可以借助序列化中的parcel对象进行实现。
实现方法如下:
3.2.1.实现一个Message的替换类MessageSub类。
MessageSub.aidl文件:
package com.zhangmiao.aidlservice; // Declare any non-default types here with import statements parcelable MessageSub;
MessageSub.java文件:
package com.zhangmiao.aidlservice; import android.os.Parcel;
import android.os.Parcelable; /**
* Created by zhangmiao on 2017/4/26.
*/ public class MessageSub implements Parcelable {
private Message message;
private String messageType;
public static final String MESSAGE_TYPE_MESSAGE = "message";
public static final String MESSAGE_TYPE_CONNECT = "connect"; public Message getMessage() {
return message;
} public void setMessage(Message message) {
this.message = message;
} public String getMessageType() {
return messageType;
} public void setMessageType(String messageType) {
this.messageType = messageType;
} public MessageSub(Message message, String messageType) {
this.message = message;
this.messageType = messageType;
} public MessageSub(Parcel parcel) {
messageType = parcel.readString();
switch (messageType) {
case MESSAGE_TYPE_CONNECT:
message = parcel.readParcelable(ConnectMessage.class.getClassLoader());
break;
default:
message = parcel.readParcelable(Message.class.getClassLoader());
break;
}
} public final static Creator<MessageSub> CREATOR = new Creator<MessageSub>() {
@Override
public MessageSub createFromParcel(Parcel source) {
return new MessageSub(source);
} @Override
public MessageSub[] newArray(int size) {
return new MessageSub[size];
}
}; @Override
public int describeContents() {
return 0;
} @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(messageType);
dest.writeParcelable(message,flags);
}
}
3.2.2修改MessageManager.aidl文件。
将添加的信息修改为MessageSub。
package com.zhangmiao.aidlservice; // Declare any non-default types here with import statements
import com.zhangmiao.aidlservice.MessageSub;
interface MessageManager {
List<MessageSub> getMessages();
void addMessage(in MessageSub message);
}
3.2.3.修改服务器端AIDL的onCreate()方法。
@Override
public void onCreate() {
super.onCreate();
Message message1 = new Message(1,"open");
MessageSub messageSub1 = new MessageSub(message1,MessageSub.MESSAGE_TYPE_MESSAGE);
mMessageList.add(messageSub1);
Message message2 = new Message(2,"get");
MessageSub messageSub2 = new MessageSub(message2,MessageSub.MESSAGE_TYPE_MESSAGE);
mMessageList.add(messageSub2);
Message connMessage = new ConnectMessage(3,"conn",1);
MessageSub messageSub3 = new MessageSub(connMessage,MessageSub.MESSAGE_TYPE_CONNECT);
mMessageList.add(messageSub3);
}
3.2.4.修改客户端的MainActivity的ServiceConnect对象的实现。
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG,"ServiceConnection onServiceConnected");
MessageManager messageManager = MessageManager.Stub.asInterface(service);
try {
List<MessageSub> messages = messageManager.getMessages();
for(int i = 0;i<messages.size();i++){
String messageType = messages.get(i).getMessageType();
Message message = messages.get(i).getMessage();
switch (messageType){
case MessageSub.MESSAGE_TYPE_MESSAGE:
Log.d(TAG,"get Message for MessageManager:"+message.toString());
break;
case MessageSub.MESSAGE_TYPE_CONNECT:
ConnectMessage connectMessage = (ConnectMessage)message;
Log.d(TAG,"get conn Message for MessageManager:"+connectMessage.toString());
break;
default:
Log.d(TAG,"get Message for MessageManager:"+message.toString());
break;
}
}
}catch (RemoteException e){
e.printStackTrace();
}
} @Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG,"ServiceConnection onServiceDisconnected");
}
};
显示结果如下图:
4.AIDL使用的注意事项
4.1. 在接口中将序列化的数据类作为接口的参数时,需要添加in/out/inout,不然会如下错误:
Error:Execution failed for task ':aidlservice:compileDebugAidl'.
> java.lang.RuntimeException: com.android.ide.common.process.ProcessException:
Error while executing process D:\sdk\build-tools\25.0.2\aidl.exe with arguments {-pD:\sdk\platforms\android-25\framework.aidl -oD:\AndroidProgram\AIDLDemo\aidlservice\build\generated\source\aidl\debug -ID:\AndroidProgram\AIDLDemo\aidlservice\src\main\aidl
-ID:\AndroidProgram\AIDLDemo\aidlservice\src\debug\aidl -IC:\Users\JackMa\.android\build-cache\2e6503c935d0e7aae874a51ce291501bd59fa172\output\aidl -IC:\Users\JackMa\.android\build-cache\a228985c661fd225e06c74ab4fc1d2ba693ed5d6\output\aidl
-IC:\Users\JackMa\.android\build-cache\04bf36b1eaa6e79d64acf7cc2ed0353331a0adb5\output\aidl -IC:\Users\JackMa\.android\build-cache\0c304484ccb4b4195fb676627e57f7ba92b2bd5e\output\aidl -IC:\Users\JackMa\.android\build-cache\07915f8984a205b1822ca99eaa0be940f26c250e\output\aidl
-IC:\Users\JackMa\.android\build-cache\a3d0bacf6fdfaf349f8eda4b777bd602fa7e5c67\output\aidl
-IC:\Users\JackMa\.android\build-cache\1d232803c59995c7bfdd0a651a144487a3f5db22\output\aidl -IC:\Users\JackMa\.android\build-cache\e18e71aa63be1e08bcc427a44b82a10769bbf421\output\aidl
-IC:\Users\JackMa\.android\build-cache\4d089e6ce66be1802231fc929e45b8b592cfa5c5\output\aidl -IC:\Users\JackMa\.android\build-cache\57b6aa97fbde28ff421267076f032edb60508e5f\output\aidl
-dC:\Users\JackMa\AppData\Local\Temp\aidl4840819892296516909.d D:\AndroidProgram\AIDLDemo\aidlservice\src\main\aidl\com\zhangmiao\aidlservice\MessageManager.aidl}
In、out、inout指的是数据流通的方式,in与out分别表示客户端与服务器之间的两条单向的数据流向,inout则表示两端可双向流通数据。
4.2. 客户端与服务器端的aidl与aidl实现的java文件要保持一致,包名也要相同。
4.3.在类实现Parcelable的接口时,在writeToParcel()与构造函数参数为Parcel的两个方法中,调用parcel的写与读数据的顺序要一致。
参考文献:
http://www.open-open.com/lib/view/open1469493649028.html
http://www.open-open.com/lib/view/open1469494852171.html
Android之AIDL知识总结的更多相关文章
- Android Programming: Pushing the Limits -- Chapter 7:Android IPC -- AIDL
服务端: 最终项目结构: 这个项目中,我们将用到自定义类CustomData作为服务端与客户端传递的数据. Step 1:创建CustomData类 package com.ldb.android.e ...
- Android 使用AIDL调用外部服务
好处:多个应用程序之间建立共同的服务机制,通过AIDL在不同应用程序之间达到数据的共享和数据相互操作, 本文包括: 1 .创建AIDL 服务端.2 .创建AIDL 客户端. 3.客户端调用服务端提供的 ...
- 详细介绍android rom移植知识普及
详细介绍android rom移植知识普及 最近接到很多兄弟们的求助,也回答过无数个和下面这个问题类似的问题: 如何编译android 原生代码得到一个rom,然后跑到某某手机上. 鉴于很多兄弟对这块 ...
- Android权限管理知识学习记录
一.Android权限背景知识 在Android 6.0之前,所申请的权限只需要在AndroidManifest.xml列举就可以了,从而容易导致一些安全隐患,因此,在Android 6.0时,Goo ...
- Android开发——Fragment知识整理(二)
0. 前言 Android开发中的Fragment的应用非常广泛,在Android开发--Fragment知识整理(一)中简单介绍了关于Fragment的生命周期,常用API,回退栈的应用等知识.这 ...
- Android开发——Fragment知识整理(一)
0. 前言 Fragment,顾名思义是片段的意思,可以把Fragment当成Activity的一个组成部分,甚至Activity的界面可以完全有不同的Fragment组成.Fragment需要被嵌 ...
- android基础---->AIDL服务的使用
AIDL和其他的IDL类似,它允许你定义程序接口,以便客户端与服务器端通过IPC机制交互.在android上面,一个进程一般不能访问另外进程的内存.因此,Android平台将这些跨进程访问的对象分解成 ...
- Android 进程间通信——AIDL
代码地址如下:http://www.demodashi.com/demo/12321.html 原文地址:http://blog.csdn.net/vnanyesheshou/article/deta ...
- Android之——AIDL深入
转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47071927 在上一篇博文<Android之--AIDL小结>中,我们 ...
随机推荐
- ThinkPhp框架:有条件的数据库查询、tp框架的其他知识
上一篇的随笔写的是基本操作,现在可以做一些高级操作,例如有条件的查询数据,有分页的条件查询数据 一.一个条件的查询数据 查询数据自然是先要显示出数据,然后根据条件进行查询数据 (1)显示出表的数据 这 ...
- WeMall的Android app商城中的wemall doraemon代码
WeMall-Android 包含SMSSDK/WeMall-Client/social_sdk_library_project三个项目以及Api目录下的client.php/update.xml接口 ...
- 小故事理解TCP/IP连接时的三次握手
在TCP/IP协议中,TCP协议通过三次握手建立一个可靠的连接,示意图如下: 下面通过一个小故事简单理解一下这三次握手的具体含义: 一天,快递员小客(客户端)准备去小服(服务器)家去送快递(准备与服务 ...
- (4)Object对象的几个常用方法
Object对象是java中对象的始祖,其有一些方法是经常需要我们来改写的: toString方法 该方法是Object的方法,Object的这的方法返回的是对象的文件结构加上对象的hashcode, ...
- 阿里安卓面试分析: Android应用的闪退(crash)问题跟踪和解析
一:问题描述 闪退(Crash)是客户端程序在运行时遭遇无法处理的异常或错误时而退出应用程序的表现,请从crash发生的原因分类与解决方法.在出现crash后如何捕捉并分析异常这两个问题给出自己 ...
- 解决mysql启动时报The server quit without updating PID file 的错误(转)
1.一般是权限问题,把用户和组改为mysql就可以了. chown -R mysql:mysql /var/lib/mysql 2.在启动mysql时报下列错误 [root@mysqld2 ~]# ...
- [Openfire]使用WebSocket建立Openfire的客户端
近日工作闲暇之余,对IM系统产生了兴趣,转而研究了IM的内容.找了半天,知道比较流行的是Openfire的系统,Openfire有许多平台实现,由于我是做Web的,所以当然是希望寻找Web的实现.Op ...
- jenkins+SVN配置
开发项目,版本控制必不可少,我用的版本控制软件为SVN,那么如何把jenkins和SVN结合,使得SVN源码一有上传更新,jenkins就马上构建项目呢?下面说一下配置过程 1) ...
- unity传送门类似效果实现
简述 在传送门中,核心的玩法是在地上或者墙上打开2个可以联通的洞来实现传送的效果.以此扩展加入解谜要素构成游戏的核心. 这里尝试使用unity来实现传送门的核心功能,具体功能分析如下: 1.传送门的模 ...
- 大数据时代日志分析平台ELK的搭建
A,首先说说ELK是啥, ELK是ElasticSearch . Logstash 和 Kiabana 三个开源工具组成.Logstash是数据源,ElasticSearch是分析数据的,Kiaba ...