在前面的文章中介紹了Messenger,Messenger的缺點就是一次只能處理一條消息坎缭,不支持多并發(fā)沮榜,而且只支持數(shù)據(jù)的傳輸,不支持方法的調(diào)用郊愧。那么在這一篇文章中 將為大家介紹更強大的IPC工具朴译,AIDL。
AIDL 全稱為Android Interface Definition Language属铁,安卓接口定義語言眠寿,也是Android實現(xiàn)IPC的方式之一。接下來將為大家介紹AIDL的使用焦蘑。
服務(wù)端:
服務(wù)端需要創(chuàng)建一個Service監(jiān)聽客戶端的連接盯拱,并創(chuàng)建AIDL文件,將暴漏給客戶端的方法在這個文件中聲明。最后在Service中實現(xiàn)AIDL中的方法狡逢。
客戶端:
綁定服務(wù)端的Service宁舰,并將Binder對象轉(zhuǎn)歡為AIDL的接口類型。
首先我們創(chuàng)建一個AIDL接口(Android Studio中通過New-> AIDL-> aidl file)
import com.ipc.www.Book;//必須顯式import
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
根據(jù)上面的代碼奢浑,AIDL中實現(xiàn)了兩個方法蛮艰,獲取Book列表和添加Book,
這里需要注意的有兩點:
1殷费、Book為實現(xiàn)了Parcelable的實體類印荔。需要注意的是Book類必須import進來,無論是否在同一個包中详羡。
2仍律、在AIDL文件的接口方法中,如果參數(shù)為實現(xiàn)了Parcelable的接口類的話实柠,參數(shù)必須標注方向水泉,in、out窒盐、inout草则。
Book.class
public class Book implements Parcelable {
private int bookId;
private String bookName;
public Book(int bookId,String bookName){
this.bookId = bookId;
this.bookName = bookName;
}
protected Book(Parcel in) {
bookId = in.readInt();
bookName = 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 parcel, int i) {
parcel.writeInt(bookId);
parcel.writeString(bookName);
}
@Override
public String toString() {
return "Book{" +
"bookId=" + bookId +
", bookName='" + bookName + '\'' +
'}';
}
}
另外,如果AIDL文件中用到了自定義的Parcelable對象時蟹漓,則必須創(chuàng)建和他同名的AIDL文件炕横,并聲明為Parcelable類型,例如Book類葡粒,Book.aidl 代碼如下份殿。
parcelable Book;
至此AIDL文件已經(jīng)創(chuàng)建完畢,接下來看服務(wù)端的實現(xiàn)嗽交。
public class BookManagerService extends Service {
private static final String Tag = "BookManagerService";
//bookList
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
// 創(chuàng)建Binder 實現(xiàn)IBookManager AIDL中的方法 并通過OnBind返回這個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);
Log.i(Tag,mBookList.toString());
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
客戶端的實現(xiàn)卿嘲。
public class AidlActivity extends AppCompatActivity {
private static final String Tag = "AidlActivity";
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//將Binder 轉(zhuǎn)換為AIDL的接口類型 即可調(diào)用aidl中的方法
IBookManager bookManager = IBookManager.Stub.asInterface(iBinder);
try {
//添加一本書
Book book = new Book(1,"我是一本書");
bookManager.addBook(book);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl);
//綁定Service
Intent intent = new Intent(this, BookManagerService.class);
bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
}
}
運行上述代碼,可以看到控制臺中成功輸出了我們添加的內(nèi)容(圖1)夫壁。
細心的小伙伴可能會問了拾枣,為什么mBookList使用CopyOnWriteArrayList而不用List呢?
這是因為CopyOnWriteArrayList支持高效率并發(fā)且是線程安全的盒让,在AIDL中梅肤,難免會存在多線程同時訪問的情況,所以在AIDL的方法中就需要做線程同步邑茄,而使用CopyOnWriteArrayList恰恰為我們省去了這部分工作凭语。
AIDL中傳輸數(shù)據(jù)都支持哪些類型呢?
1撩扒、基本數(shù)據(jù)類型;
2、String和CharSequence搓谆;
3炒辉、ArrayList,HashMap泉手,且其中的每個元素必須能夠被AIDL支持黔寇。
4、實現(xiàn)了Parcelable的對象斩萌。
5缝裤、AIDL接口本身。