IPC之AIDL的简单使用

参考Android开发艺术探索

AIDL

实现流程

  1. 服务端

    服务端首先要创建一个Service 用来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL中声明,最后在Service 中实现这个 AIDL接口即可

  2. 客户端

    首先需要绑定服务端的Service,绑定成功之后,将服务端返回的 Binder 对象转成 AIDL 接口所属的类型,接着就可以调用AIDL 中的方法了。

  3. AIDL接口的创建

    具体的aidl 文件的创建方式参考2018-07-17-Binder。

代码实现

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 getBookList();
    void addBook(in Book book);
    void registerListener(IOnNewBookArrivedListener listener);
    void unregisterListener(IOnNewBookArrivedListener listener);
}

服务端

 */
class BookManagerService : Service() {

    /**
     * 线程安全的,系统提供的原子类,我们不需要自己线程同步的问题,内部封装中已经为我们处理好了
     */
    private val mBookList = CopyOnWriteArrayList()
    private val mIsServiceDestroyed = AtomicBoolean(false)

    /**
     * 专门用来进程通信中处理回调的类,以当前 binder 对象作为 key。
     *
     * 因为在底层实现中,服务端与客户端只有 binder 对象是共有的,其余的对象都是序列化的传输,无法作为key
     */
    private val mListenerList = RemoteCallbackList()


    private val mBinder = object : IBookManager.Stub() {

        /*这里的方法 都是工作在服务端的 Binder 线程池中的,直接同步操作即可*/

        override fun registerListener(listener: IOnNewBookArrivedListener?) {
            mListenerList.register(listener)
        }

        override fun unregisterListener(listener: IOnNewBookArrivedListener?) {
            mListenerList.unregister(listener)
        }

        override fun getBookList(): MutableList {
            return mBookList
        }

        override fun addBook(book: Book?) {
            mBookList.add(book)
        }
    }

    /**
     * 创建一个线程用来不停的添加新的书籍,并通知所有注册提醒服务的客户端:有新书到达
     */
    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 线程的标记位
        mIsServiceDestroyed.set(true)
        super.onDestroy()
    }

    override fun onBind(intent: Intent?): IBinder {
        return mBinder
    }

    /**
     * 有新书到达时,通知所有注册提醒服务的客户端
     */
    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

    /**
     * 服务端通知客户端新书到达的监听回调
     *
     * 此方法最终的执行是在客户端的Binder线程池中执行的
     */
    private val mOnNewBookArrivedListener = object : IOnNewBookArrivedListener.Stub() {
        override fun onNewBookArrived(newBook: Book?) {
            mHandler.obtainMessage(MSG_NEW_BOOK_ARRIVED, newBook).sendToTarget()
        }
    }

    /**
     * 由于mOnNewBookArrivedListener回调的执行是在客户端的Binder线程池中执行的,为了便于UI操作,利用Handler将其切换到客户端的主线程中去执行。
     */
    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线程中运行的,所以不可以在这里直接调用服务端的耗时操作*/

        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 开发艺术探索"))
            val newList = bookManager.bookList
            Log.i(TAG, "query book list: $newList")
            //注册mOnNewBookArrivedListener监听到远程服务端
            bookManager.registerListener(mOnNewBookArrivedListener)
        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_book_manager)
        //绑定服务
        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 中的元素个数

耗时操作

        override fun getBookList(): MutableList {
            //模拟耗时操作
            SystemClock.sleep(5000)
            return mBookList
        }

那么客户端在调用 getBookList 的时候需要在子线程中处理,以防ANR的出现。

权限验证

  • onBind中做处理
  • onTransact中做处理

处理逻辑基本差不多。

自定义权限:


验证代码:

    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 中重连
  • 设置 DeathRecipient 监听

你可能感兴趣的:(IPC之AIDL的简单使用)