简介
AIDL:Android Interface Definition Language,即Android接口定义语言,用于生成Android不同进程间进行进程通信(IPC)的代码,一般情况下一个进程是无法访问另一个进程的内存的。如果某些情况下仍然需要跨进程访问内存数据,这时候Android系统就要将其对象分解成能够识别的原数据,编写这一组操作的代码是一项繁琐的工作,但是AIDL对底层进行了抽象的封装,简化了跨进程操作。
AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据。
接下来介绍在AndroidStudio中使用ALDL在进程间通讯(也就是两个应用的通讯)分别从服务端和客户端两个方面
1. 服务端:
服务端首先要创建一个Service用来监听客户端的连接请求,然后创建ALDL文件,将暴露给客户端的接口在这个ALDL文件的申明,最后在Service中实现这个ALDL的接口实现
2. 客户端:
客户端首先需要绑定服务端的Service,绑定成功之后,将服务器返回的Binder对象转换成ALDL接口所属的类型,接着就可以调用ALDL中的方法
3. ALDL接口的创建:
首先看ALDL接口的创建,如下所示,我们创建
自定义类要实现Parcelable
服务端的ALDL部署
/**
*自定义类型
**/
public class Book implements Parcelable {
private int bookId;
private String bookName;
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
public int getBookId() {
return bookId;
}
public void setBookId(int bookId) {
this.bookId = bookId;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.bookId);
dest.writeString(this.bookName);
}
public Book() {
}
protected Book(Parcel in) {
this.bookId = in.readInt();
this.bookName = in.readString();
}
public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
@Override
public Book createFromParcel(Parcel source) {
return new Book(source);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public String toString() {
return "Book{" +
"bookId=" + bookId +
", bookName='" + bookName + '\'' +
'}';
}
}
下面是两个ALDL文件
Book.aidl
// Book.aidl
package com.example.administrator.wuandy;
// Declare any non-default types here with import statements
//ALDL中使用自定义的Parcelable为其声明类型
parcelable Book;
IBookManger.aidl
// IBookManger.aidl
package com.example.administrator.wuandy;
import com.example.administrator.wuandy.Book;
// Declare any non-default types here with import statements
interface IBookManger {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
List<Book>getBookList();
void addBook(in Book book);
String getBookName();
}
运行你的aidl会报错,log显示找不到Book的定义,没错现在你的Book在aidl包下,编译时不会去它下面找类,此时你需要做以下工作,在build.gradle文件中加入以下代码。。
sourceSets{
main{
java.srcDirs = ['src/main/java', 'src/main/aidl']
}
}
编译成功之后会出现
ALDL文件支持的格式那些数据类型呢?如下所示
- 基本数据类型
- String和CharSequence
- list:只支持ArrayList,里面的每个元素都必须能够被ALDL支持
- Map:只支持HashMap,里面的每个元素都必须被ALDL支持,包括key和value
- Parcelable:所有实现了Parcelable的对象
- ALDL:所有ALDL接口本身也可以在ALDL文件中使用
注意
1.ALDL中除了基本数据类型,其他类型的参数必须表上方向:in 、out、inout,in表示输入型参数,out表示输出型参数,inout表示输入输出型参数
2. ALDL接口中只支持方法,不支持声明静态变量,
3.为了方便ALDL开发,建议将所有和ALDL相关的类和文件全部放入同一个包中,这样我们可以直接将整个包复制到客户端工程中,ALDL包的结构在客户端和服务端保持一致,否则会错。因为客户端要反序列化服务端中和ALDL接口相关的所有类,如果类的完整路径不对就无法成功反序列化。
4.远程服务端Service的实现
package com.example.administrator.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import com.example.administrator.wuandy.Book;
import com.example.administrator.wuandy.IBookManger;
import com.orhanobut.logger.Logger;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2018/2/8.
*/
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
class MyBinder extends IBookManger.Stub{
private List<Book> books=new ArrayList<>();
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public List<Book> getBookList() throws RemoteException {
Book book=new Book(1,"ANDROID");
books.add(book);
Book book1=new Book(2,"IOS");
books.add(book1);
Logger.d("MyBinder:集合_getBookList()"+books.size());
return books;
}
@Override
public void addBook(Book book) throws RemoteException {
books.add(book);
Logger.d("MyBinder:集合_addBook()"+books.size());
}
@Override
public String getBookName() throws RemoteException {
return "Java";
}
}
}
Service的注册
<service android:name="com.example.administrator.service.MyService"
android:exported="true">
<intent-filter>
<action android:name="com.Andy.ALDL"></action>
</intent-filter>
</service>
5.客户端的实现
package com.example.administrator.wuandy;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private IBookManger iBookManger;
private Button start;
private TextView content;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start=findViewById(R.id.start);
content=findViewById(R.id.content);
start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent();
intent.setAction("com.Andy.ALDL");
intent.setPackage("com.example.administrator.wuandy");
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iBookManger=IBookManger.Stub.asInterface(service);
Toast.makeText(MainActivity.this,"远程服务连接上了",Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
},BIND_AUTO_CREATE);
}
});
content.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
content.setText(iBookManger.getBookList().toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onDestroy() {
//注意要解绑
super.onDestroy();
}
}
最后贴上运行之后的效果