歡迎Follow我的GitHub, 關(guān)注我的簡(jiǎn)書(shū). 其余參考Android目錄.
本文的合集已經(jīng)編著成書(shū)舔示,高級(jí)Android開(kāi)發(fā)強(qiáng)化實(shí)戰(zhàn)驶社,歡迎各位讀友的建議和指導(dǎo)。在京東即可購(gòu)買(mǎi):https://item.jd.com/12385680.html
AIDL(Android Interface Definition Language), 即Android接口定義語(yǔ)言. 在Android中, AIDL是跨進(jìn)程通信的主要實(shí)現(xiàn)方式. 我們同樣也可以使用AIDL, 實(shí)現(xiàn)自己的跨進(jìn)程方案. 本文介紹AIDL的使用方式.
服務(wù)端: 創(chuàng)建Service服務(wù)監(jiān)聽(tīng)客戶端的請(qǐng)求, 實(shí)現(xiàn)AIDL接口.
客戶端: 綁定服務(wù)端, 調(diào)用AIDL的方法.
AIDL接口: 跨進(jìn)程通信的接口, AIDL的包名需要與項(xiàng)目的包名相同, 默認(rèn)生成即可.
AIDL支持的數(shù)據(jù)類型: 基本類型, 字符串類型(String&CharSequence), List, Map, Parcelable, AIDL接口. 共六種.
流程: 客戶端注冊(cè)服務(wù)端, 服務(wù)端添加新書(shū), 客戶端接收, 并提供客戶端的查詢書(shū)數(shù)量的接口.
本文源碼的GitHub下載地址
AIDL
本文使用自定義的數(shù)據(jù)類型Book類, 實(shí)現(xiàn)Parcelable接口, 具體參考.
public class Book implements Parcelable {
public int bookId;
public String bookName;
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
@Override public int describeContents() {
return 0;
}
@Override public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(bookId);
dest.writeString(bookName);
}
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];
}
};
private Book(Parcel source) {
bookId = source.readInt();
bookName = source.readString();
}
@Override public String toString() {
return "ID: " + bookId + ", BookName: " + bookName;
}
}
AIDL使用自定義類, 需要聲明Parcelable類.
// IBook.aidl
package org.wangchenlong.wcl_aidl_demo;
// Declare any non-default types here with import statements
parcelable Book;
添加AIDL的接口, 用于通知新書(shū)到達(dá).
// IOnNewBookArrivedListener.aidl
package org.wangchenlong.wcl_aidl_demo;
// Declare any non-default types here with import statements
import org.wangchenlong.wcl_aidl_demo.Book;
interface IOnNewBookArrivedListener {
/**
* 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 onNewBookArrived(in Book newBook);
}
AIDL文件注釋較多, 都是自動(dòng)生成, 不影響閱讀.
核心AIDL類, 書(shū)籍管理器, 四個(gè)方法, 獲取圖書(shū)列表, 添加書(shū)籍, 注冊(cè)接口, 解注冊(cè)接口. 注意, 使用其他方法, 需要import導(dǎo)入相應(yīng)文件.
// IBookManager.aidl
package org.wangchenlong.wcl_aidl_demo;
// Declare any non-default types here with import statements
import org.wangchenlong.wcl_aidl_demo.Book;
import org.wangchenlong.wcl_aidl_demo.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);
List<Book> getBookList(); // 返回書(shū)籍列表
void addBook(in Book book); // 添加書(shū)籍
void registerListener(IOnNewBookArrivedListener listener); // 注冊(cè)接口
void unregisterListener(IOnNewBookArrivedListener listener); // 注冊(cè)接口
}
所有的參數(shù)都需要標(biāo)注參數(shù)方向, in表示輸入類型, out表示輸出類型, inout表示輸入輸出類型. out與inout的開(kāi)銷(xiāo)較大, 不能統(tǒng)一使用高級(jí)方向.
服務(wù)端
服務(wù)端通過(guò)Binder實(shí)現(xiàn)AIDL的IBookManager.Stub
接口.
private Binder mBinder = new IBookManager.Stub() {
@Override public List<Book> getBookList() throws RemoteException {
SystemClock.sleep(5000); // 延遲加載
return mBookList;
}
@Override public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
@Override
public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
mListenerList.register(listener);
int num = mListenerList.beginBroadcast();
mListenerList.finishBroadcast();
Log.e(TAG, "添加完成, 注冊(cè)接口數(shù): " + num);
}
@Override
public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
mListenerList.unregister(listener);
int num = mListenerList.beginBroadcast();
mListenerList.finishBroadcast();
Log.e(TAG, "刪除完成, 注冊(cè)接口數(shù): " + num);
}
};
服務(wù)啟動(dòng)時(shí), 添加兩本新書(shū), 并使用線程繼續(xù)添加.
@Override public void onCreate() {
super.onCreate();
mBookList.add(new Book(1, "Android"));
mBookList.add(new Book(2, "iOS"));
new Thread(new ServiceWorker()).start();
}
添加書(shū)籍, 并發(fā)送通知.
private class ServiceWorker implements Runnable {
@Override public void run() {
while (!mIsServiceDestroyed.get()) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
num++;
if (num == 5) {
mIsServiceDestroyed.set(true);
}
Message msg = new Message();
mHandler.sendMessage(msg); // 向Handler發(fā)送消息,更新UI
}
}
}
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
int bookId = 1 + mBookList.size();
Book newBook = new Book(bookId, "新書(shū)#" + bookId);
try {
onNewBookArrived(newBook);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
向注冊(cè)監(jiān)聽(tīng)的, 發(fā)送新書(shū)的添加通知.
private void onNewBookArrived(Book book) throws RemoteException {
mBookList.add(book);
Log.e(TAG, "發(fā)送通知的數(shù)量: " + mBookList.size());
int num = mListenerList.beginBroadcast();
for (int i = 0; i < num; ++i) {
IOnNewBookArrivedListener listener = mListenerList.getBroadcastItem(i);
Log.e(TAG, "發(fā)送通知: " + listener.toString());
listener.onNewBookArrived(book);
}
mListenerList.finishBroadcast();
}
在AndroidManifest中, Service與Activity不在同一進(jìn)程.
<!--與主應(yīng)用不在同一進(jìn)程中-->
<service
android:name=".BookManagerService"
android:process=":remote"/>
客戶端
綁定服務(wù)和解綁服務(wù), 綁定服務(wù)的具體內(nèi)容, 都是在mConnection
中實(shí)現(xiàn).
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.main_tv_book_list);
}
@Override protected void onDestroy() {
if (mRemoteBookManager != null && mRemoteBookManager.asBinder().isBinderAlive()) {
try {
Log.e(TAG, "解除注冊(cè)");
mRemoteBookManager.unregisterListener(mOnNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(mConnection);
super.onDestroy();
}
添加內(nèi)容, 注冊(cè)監(jiān)聽(tīng)接口.
private ServiceConnection mConnection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager bookManager = IBookManager.Stub.asInterface(service);
try {
mRemoteBookManager = bookManager;
Book newBook = new Book(3, "學(xué)姐的故事");
bookManager.addBook(newBook);
new BookListAsyncTask().execute();
bookManager.registerListener(mOnNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override public void onServiceDisconnected(ComponentName name) {
mRemoteBookManager = null;
Log.e(TAG, "綁定結(jié)束");
}
};
當(dāng)調(diào)用監(jiān)聽(tīng)接口時(shí), 異步顯示圖書(shū)列表.
private IOnNewBookArrivedListener mOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() {
@Override public void onNewBookArrived(Book newBook) throws RemoteException {
mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED, newBook).sendToTarget();
}
};
private Handler mHandler = new Handler() {
@Override public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_NEW_BOOK_ARRIVED:
Log.e(TAG, "收到的新書(shū): " + msg.obj);
new BookListAsyncTask().execute();
break;
default:
super.handleMessage(msg);
break;
}
}
};
點(diǎn)擊綁定服務(wù)
按鈕, 執(zhí)行綁定服務(wù). 點(diǎn)擊獲取圖書(shū)數(shù)量
按鈕, 獲取當(dāng)前列表的數(shù)量.
效果
Android跨進(jìn)程通信比較復(fù)雜, 但是意義重大, 目前常用的動(dòng)態(tài)加載框架都需要處理跨進(jìn)程通信等問(wèn)題, 熟練基本原理, 掌握使用方式.
OK, that's all! Enjoy it!