参考Android开发艺术探索
AIDL
实现流程
-
服务端
服务端首先要创建一个Service 用来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL中声明,最后在Service 中实现这个 AIDL接口即可
-
客户端
首先需要绑定服务端的Service,绑定成功之后,将服务端返回的 Binder 对象转成 AIDL 接口所属的类型,接着就可以调用AIDL 中的方法了。
-
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 监听