參考Android開發(fā)藝術(shù)探索
AIDL
實現(xiàn)流程
-
服務(wù)端
服務(wù)端首先要創(chuàng)建一個Service 用來監(jiān)聽客戶端的連接請求,然后創(chuàng)建一個AIDL文件,將暴露給客戶端的接口在這個AIDL中聲明,最后在Service 中實現(xiàn)這個 AIDL接口即可
-
客戶端
首先需要綁定服務(wù)端的Service,綁定成功之后,將服務(wù)端返回的 Binder 對象轉(zhuǎn)成 AIDL 接口所屬的類型,接著就可以調(diào)用AIDL 中的方法了。
-
AIDL接口的創(chuàng)建
具體的aidl 文件的創(chuàng)建方式參考2018-07-17-Binder。
代碼實現(xiàn)
aidl
Book.aidl
// IMyAidlInterface.aidl
package com.xianjin.loan.aidl;
// Declare any non-default types here with import statements
parcelable Book;
IOnNewBookArrivedListener.aidl
// IOnNewBookArrivedListener.aidl
package com.xianjin.loan.aidl;
// Declare any non-default types here with import statements
import com.xianjin.loan.aidl.Book;
interface IOnNewBookArrivedListener {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void onNewBookArrived(in Book newBook);
}
IBookManager.aidl
// IBookManager.aidl
package com.xianjin.loan.aidl;
// Declare any non-default types here with import statements
import com.xianjin.loan.aidl.Book;
import com.xianjin.loan.aidl.IOnNewBookArrivedListener;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
void registerListener(IOnNewBookArrivedListener listener);
void unregisterListener(IOnNewBookArrivedListener listener);
}
服務(wù)端
*/
class BookManagerService : Service() {
/**
* 線程安全的,系統(tǒng)提供的原子類,我們不需要自己線程同步的問題,內(nèi)部封裝中已經(jīng)為我們處理好了
*/
private val mBookList = CopyOnWriteArrayList<Book>()
private val mIsServiceDestroyed = AtomicBoolean(false)
/**
* 專門用來進程通信中處理回調(diào)的類,以當(dāng)前 binder 對象作為 key。
*
* 因為在底層實現(xiàn)中,服務(wù)端與客戶端只有 binder 對象是共有的,其余的對象都是序列化的傳輸,無法作為key
*/
private val mListenerList = RemoteCallbackList<IOnNewBookArrivedListener>()
private val mBinder = object : IBookManager.Stub() {
/*這里的方法 都是工作在服務(wù)端的 Binder 線程池中的,直接同步操作即可*/
override fun registerListener(listener: IOnNewBookArrivedListener?) {
mListenerList.register(listener)
}
override fun unregisterListener(listener: IOnNewBookArrivedListener?) {
mListenerList.unregister(listener)
}
override fun getBookList(): MutableList<Book> {
return mBookList
}
override fun addBook(book: Book?) {
mBookList.add(book)
}
}
/**
* 創(chuàng)建一個線程用來不停的添加新的書籍,并通知所有注冊提醒服務(wù)的客戶端:有新書到達
*/
private val mWorkerThread = Thread(Runnable {
while (!mIsServiceDestroyed.get()) {
Thread.sleep(5000)
val bookId = mBookList.size + 1
val book = Book(bookId, "new book #$bookId")
mBookList.add(book)
onNewBookArrived(book)
}
})
override fun onCreate() {
super.onCreate()
mBookList.add(Book(1, "Android"))
mBookList.add(Book(2, "iOS"))
mWorkerThread.start()
}
override fun onDestroy() {
//用來停止 mWorkerThread 線程的標(biāo)記位
mIsServiceDestroyed.set(true)
super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder {
return mBinder
}
/**
* 有新書到達時,通知所有注冊提醒服務(wù)的客戶端
*/
private fun onNewBookArrived(book: Book) {
val num = mListenerList.beginBroadcast()
for (i in 0 until num) {
val item = mListenerList.getBroadcastItem(i)
item.onNewBookArrived(book)
}
mListenerList.finishBroadcast()
}
}
客戶端
class BookManagerActivity : AppCompatActivity() {
private var mRemoteBookManager: IBookManager? = null
/**
* 服務(wù)端通知客戶端新書到達的監(jiān)聽回調(diào)
*
* 此方法最終的執(zhí)行是在客戶端的Binder線程池中執(zhí)行的
*/
private val mOnNewBookArrivedListener = object : IOnNewBookArrivedListener.Stub() {
override fun onNewBookArrived(newBook: Book?) {
mHandler.obtainMessage(MSG_NEW_BOOK_ARRIVED, newBook).sendToTarget()
}
}
/**
* 由于mOnNewBookArrivedListener回調(diào)的執(zhí)行是在客戶端的Binder線程池中執(zhí)行的,為了便于UI操作,利用Handler將其切換到客戶端的主線程中去執(zhí)行。
*/
private val mHandler = Handler(Handler.Callback {
when (it.what) {
MSG_NEW_BOOK_ARRIVED -> Log.d(TAG, "receive new book : " + it.obj)
}
true
})
private val mConnection = object : ServiceConnection {
/*由于這個兩個方法的都是在客戶端的UI線程中運行的,所以不可以在這里直接調(diào)用服務(wù)端的耗時操作*/
override fun onServiceDisconnected(name: ComponentName?) {
//todo: 可以在這里處理Binder死亡后重新連接的邏輯
mRemoteBookManager = null
Log.e(TAG, "binder died")
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val bookManager = IBookManager.Stub.asInterface(service)
mRemoteBookManager = bookManager
val list = bookManager.bookList
Log.i(TAG, "query book list , list type: " + list.javaClass.canonicalName)
Log.i(TAG, "query book list: $list")
bookManager.addBook(Book(3, "Android 開發(fā)藝術(shù)探索"))
val newList = bookManager.bookList
Log.i(TAG, "query book list: $newList")
//注冊mOnNewBookArrivedListener監(jiān)聽到遠程服務(wù)端
bookManager.registerListener(mOnNewBookArrivedListener)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_book_manager)
//綁定服務(wù)
bindService(Intent(this, BookManagerService::class.java), mConnection, Context.BIND_AUTO_CREATE)
}
override fun onDestroy() {
if (mRemoteBookManager != null && mRemoteBookManager!!.asBinder().isBinderAlive) {
mRemoteBookManager?.unregisterListener(mOnNewBookArrivedListener)
mRemoteBookManager = null
}
unbindService(mConnection)
super.onDestroy()
}
companion object {
const val TAG = "BookManagerActivity"
const val MSG_NEW_BOOK_ARRIVED = 1
}
}
RemoteCallbackList
- beginBroadcast
- finishBroadcast
這兩個方法必須要配對使用,哪怕是僅僅是想要獲取 RemoteCallbackList 中的元素個數(shù)
耗時操作
override fun getBookList(): MutableList<Book> {
//模擬耗時操作
SystemClock.sleep(5000)
return mBookList
}
那么客戶端在調(diào)用 getBookList 的時候需要在子線程中處理,以防ANR的出現(xiàn)。
權(quán)限驗證
- onBind中做處理
- onTransact中做處理
處理邏輯基本差不多。
自定義權(quán)限:
<permission
android:name="com.xianjin.loan.permission.ACCESS_BOOK_SERVICE"
android:protectionLevel="normal"/>
驗證代碼:
override fun onBind(intent: Intent?): IBinder? {
val check = checkCallingOrSelfPermission("com.xianjin.loan.ACCESS_BOOK_SERVICE")
if (check == PackageManager.PERMISSION_DENIED) {
return null
}
return mBinder
}
Binder 死亡處理
- onServiceDisconnected 中重連
- 設(shè)置 DeathRecipient 監(jiān)聽