IPC之AIDL的簡單使用

參考Android開發(fā)藝術(shù)探索

AIDL

實現(xiàn)流程

  1. 服務(wù)端

    服務(wù)端首先要創(chuàng)建一個Service 用來監(jiān)聽客戶端的連接請求,然后創(chuàng)建一個AIDL文件,將暴露給客戶端的接口在這個AIDL中聲明,最后在Service 中實現(xiàn)這個 AIDL接口即可

  2. 客戶端

    首先需要綁定服務(wù)端的Service,綁定成功之后,將服務(wù)端返回的 Binder 對象轉(zhuǎn)成 AIDL 接口所屬的類型,接著就可以調(diào)用AIDL 中的方法了。

  3. 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)聽
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容