【Android开发艺术】读懂AIDL系列文章(一)
一、先上Github源码地址:Aidl
二、写一个简单的Aidl使用:
1、Aidl的应用场景:
进程间通信或者不同App间通信(此处写为服务端servelapp和客户端clientapp)
举例:服务端用来提供数据,客户端从服务端查询数据和新增数据。
1.1、服务端
写一个activity用来启动service(其实这一步可以省略)。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void click(View view){
startService(new Intent(this, BookManagerService.class));
}
}
写BookManagerService服务端
public class BookManagerService extends Service {
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
private Binder mBinder = new IBookManager.Stub(){
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
};
public BookManagerService() {
}
@Override
public void onCreate() {
super.onCreate();
mBookList.add(new Book(1,"Android"));
mBookList.add(new Book(2,"Ios"));
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mBinder;
}
其中
1、第二行CopyOnWriteArrayList:多线程访问用来在AIDL中处理线程同步;
2、第3-12行:service返回的mBinder通过AIDL接口IBookManager的Stub方法获得一个Binder对象。
private Binder mBinder = new IBookManager.Stub(){
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
};
此处用到了aidl生成的Binder类。实际上是通过自动生成的Binder类IBookManager.java来实现进程间通信。(也就是我们可以绕开aidl自己手工实现Binder进程间通信,只不过aidl让这个过程变成了透明,变得非常简单)。
注释:如何新建一个IBookManager.aidl
新建的aidl接口如下格式:
package haibo.com.servelapp;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* 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);
}
修改成我们需要的aidl接口后如下:
// IBookManager.aidl
package haibo.com.servelapp;
// Declare any non-default types here with import statements
import haibo.com.servelapp.Book;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
其中Book需要手动导入import,即使在同一个包中。另外,除了基本数据类型外,其他类型,需要加上in out inout其中之一,表示输入输出类型参数。
import haibo.com.servelapp.Book;
此处的Book并不是Book.java而是Book.aidl接口,因为aidl接口中只能访问aidl接口。如下:
// Book.aidl
package haibo.com.servelapp;
// Declare any non-default types here with import statements
parcelable Book;
此处再引用Book的序列化对象如下:Book类需要是实现Android序列化接口的类,因为aidl通信的对象是一个序列化和反序列化的过程。
package haibo.com.servelapp;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by user on 2018/1/26.
*/
public class Book implements Parcelable {
private int id;
private String name;
public Book(int id, String name) {
this.id = id;
this.name = name;
}
protected Book(Parcel in) {
id = in.readInt();
name = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
最后需要注意的两点,也是容易忽略的两点,如果需要让其他进程访问当前服务端的service,需要在manifest中设置访问action
<service
android:name=".service.BookManagerService"
android:enabled="true"
android:exported="true"
>
<intent-filter>
<action android:name="haibo.com.servelapp.service.BookManagerService" />
</intent-filter>
</service>
此处有一个坑,Android Studio中构建aidl对象的时候会发现找不到Book类。需要在gradle文件中配置如下:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
applicationId "haibo.com.servelapp"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/main/aidl']
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
}
其中此处为需要配置的地方
sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/main/aidl']
}
}
1.2、客户端:
客户端需要完全复制服务端的aidl包。完全复制,完全复制,完全复制,重要的事情说三遍!不要改包名,不要改任何东西。
客户端代码比较简单,直接上代码:
public class MainActivity extends Activity {
private TextView textView;
private EditText edit_query;
private IBookManager bookManager;
private static int count = 0;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IBookManager.Stub.asInterface(service);
try {
List<Book> list = bookManager.getBookList();
count = list.size();
textView.setText("getBookList结果是:list.toString());
Log.e("MainActivity",list.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.booklist);
edit_query = (EditText) findViewById(R.id.edit_query);
//初始化启动service
Intent intent = new Intent("haibo.com.servelapp.service.BookManagerService");
bindService(intent,connection, Context.BIND_AUTO_CREATE);
}
public void addBook(View view) throws RemoteException {
//添加一本书并展示
String str = edit_query.getText().toString();
if (!TextUtils.isEmpty(str)){
coun;
bookManager.addBook(new Book(count,str));
}
List<Book> newlist = bookManager.getBookList();
textView.setText("新getBookList结果是:newlist.toString());
Log.e("MainActivity",newlist.toString());
}
}
第34,35行,通过bindService建立连接。
//初始化启动service
Intent intent = new Intent("haibo.com.servelapp.service.BookManagerService");
bindService(intent,connection, Context.BIND_AUTO_CREATE);
第9行,在连接中获取aidl接口IBookManager
bookManager = IBookManager.Stub.asInterface(service);
至此,就完成了第一版本的aidl进程间通信代码,实现了客户端访问服务端的书籍数据,并向服务端添加书籍。
此处代码在github中第一次提交( )的代码可见。
本文完,
AIDL未完待续。