上文中介绍了对象的序列化和Binder的使用,这篇文章主要介绍AndroidStudio开发AIDL的过程,如果没有看过上一篇的可以移步Anddroid中Binder的用法和对象的序列化
实现的功能大致是在主进程的Activity中调用其他进程中的方法。
Android的SDK会帮助我们自动生成Binder类。
第一步:创建图书管理的接口aidl文件,右键
选择创建AIDL FILE,这里我们选择穿件一个接口IBookManager
这接口里封装了两个方法代码如下:
// IBookManager.aidl
package com.lizhi.demo.ipc.aidl;
// Declare any non-default types here with import statements
import com.lizhi.demo.ipc.aidl.Book;
import com.lizhi.demo.ipc.aidl.IOnNewBookArrivedListener;
interface IBookManager {
/**
* 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);
void addBook(in Book book);
List<Book> getBookList();
}
这时候AndroidStudio会默认为我们创建一个包
如图所示上面的aidl包就是AndroidStudio默认给我创建的和我们自己建立的包是完全一样的。接口里有两个方法addBook
和getBookList
注意addBook的方法参数有个in
这是aidl文件特有的表示输入行参数,除了in
还有out
,ountin
第二步:创建实体类Book实现Percalable接口代码:
package com.lizhi.demo.ipc.aidl;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by Administrator on 2015/12/30.
*/
public class Book implements Parcelable {
public Book(String bookName, String bookId) {
this.bookName = bookName;
this.bookId = bookId;
}
public String bookName;
public String bookId;
protected Book(Parcel in) {
bookName = in.readString();
bookId = in.readString();
}
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 int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(bookName);
dest.writeString(bookId);
}
@Override
public String toString() {
return "Book{" +
"bookName='" + bookName + '\'' +
", bookId='" + bookId + '\'' +
'}';
}
}
注意这个是个java类创建在我们自己的包中(不是AndroidStudio给我生成的那个包)然后创建这个Book对应的aidl文件(在系统帮我们生成的包中创建),为什么要创建呢?因为在aidl中不能引用java类所以我们要自己创建一个。Book.aidl文件如下:
package com.lizhi.demo.ipc.aidl;
parcelable Book;
很简单 就指定这个类是Parcelable类型的就行了。
你有可能注意到在IBookManager.aidl中我们
即使他俩在同一个包中,这就是aidl特有的。
import com.lizhi.demo.ipc.aidl.Book;
实现上面两步后我们就开始下Activity和Sercice了
在Activity中很简单 只需要绑定Service就好了
Intent aidlIntent = new Intent();
aidlIntent.setClass(this, AidlSercice.class);
boolean aidlBind = bindService(aidlIntent, aidlConnection, Context.BIND_AUTO_CREATE);
LogUtil.log("-------aidlBind------->" + aidlBind);
ServiceConnection aidlConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iBookManager = IBookManager.Stub.asInterface(service);
List<Book> bookList = null;
try {
bookList = iBookManager.getBookList();
LogUtil.log("---------aidl----->" + bookList.getClass().getCanonicalName());
LogUtil.log("-------aidl--toString----->" + bookList.toString());
iBookManager.registerListener(onNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
LogUtil.log("-------aidl--onServiceDisconnected----->");
}
};
在ServiceConnection
的onServiceConnected
中我们拿到IBookManager
通过这个接口就可进行添加和获取列表的方法了
接下来我们在看看Service中的实现:
package com.lizhi.demo.ipc;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.support.annotation.BoolRes;
import android.support.annotation.Nullable;
import com.lizhi.demo.ipc.aidl.Book;
import com.lizhi.demo.ipc.aidl.IBookManager;
import com.lizhi.demo.ipc.aidl.IOnNewBookArrivedListener;
import com.lizhi.demo.utils.LogUtil;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Created by Administrator on 2015/12/30.
*/
public class AidlSercice extends Service {
//线程安全的List
CopyOnWriteArrayList<Book> mList = new CopyOnWriteArrayList<>();
// CopyOnWriteArrayList<IOnNewBookArrivedListener> listeners = new CopyOnWriteArrayList<>();
RemoteCallbackList<IOnNewBookArrivedListener> listeners = new RemoteCallbackList<>();
int count;
@Override
public void onCreate() {
super.onCreate();
mList.add(new Book("葵花宝典", "1"));
mList.add(new Book("皮鞋简朴", "2"));
LogUtil.log("--------onCreate-----");
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
onNewBoolAdd(new Book("" + count, "" + count));
count++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
Binder mBinder = new IBookManager.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public void addBook(Book book) throws RemoteException {
LogUtil.log("---------addBook-------addBook------" + book);
mList.add(book);
}
@Override
public List<Book> getBookList() throws RemoteException {
LogUtil.log("---------AidlSercice-------getBookList------" + mList);
return mList;
}
@Override
public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
listeners.register(listener);
}
@Override
public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
listeners.unregister(listener);
}
};
public void onNewBoolAdd(Book book) {
final int N = listeners.beginBroadcast();
for (int i = 0; i < N; i++) {
IOnNewBookArrivedListener l = listeners.getBroadcastItem(i);
if (l != null) {
try {
l.onNetBookArrived(book);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
listeners.finishBroadcast();
mList.add(book);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
在Service的onBind
方法中我们返回IBookManager.Stub
对象,这个对象就是一个Binder对象可以进行夸进程的通信。至于Stub这个对象是IbookManager接口的内部类,系统帮我们生成一个,在Activity中的onServiceConnected
中我们调用了iBookManager = IBookManager.Stub.asInterface(service);
这个方法生成Service里的接口对象。asInterface
这个方法会进行判断如果是夸进程则生成一个夸进程的代理可以进行进程间的通信如果不是夸进程则返回对象本身。
这里只是实现简单的通信功能,其实进程间通信还有许多需要考虑的东西。大家可以慢慢挖掘。
最后说说注意事项:
在ServiceConnextion
中的
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iBookManager = IBookManager.Stub.asInterface(service);
List<Book> bookList = null;
try {
bookList = iBookManager.getBookList();
LogUtil.log("---------aidl----->" + bookList.getClass().getCanonicalName());
LogUtil.log("-------aidl--toString----->" + bookList.toString());
iBookManager.registerListener(onNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
方法中我调用了其他进程的方法,这里的onServiceConnected
是运行在UI线程的如果其他进程的方法是个耗时的操作则不能这样写了 需要开启线程
Service里的方法是运行在Binder线程里的所以这些方法是可以运行耗时操作的不需要在开启线程了。