@cxm-2016
2016-08-17T10:02:30.000000Z
字数 4330
阅读 1726
android
no
至于AIDL的基本使用方法这里就不再介绍,可以参看博文Android Studio中使用Kotlin语言实现AIDL通信[图文] 。这篇博文通过一个简单的接口实现回复客户端发送的字符串功能来介绍了AIDL工程的创建。
按照我们标题1中的基本示例仅仅是客户端主动调用服务端的方法,可是我们如果要实现服务端主动联系客户端应该怎么办?
下面我们使用一个服务端每5秒钟向客户端发送一条消息的例子来展示如何设置回调。
// IMessageCallback.aidl
package aidl;
// Declare any non-default types here with import statements
interface IMessageCallback {
void message(String message);
}
// IMessageHandler.aidl
package aidl;
// Declare any non-default types here with import statements
import aidl.IMessageCallback;
interface IMessageHandler {
void register(IMessageCallback callback);
void unregister(IMessageCallback callback);
}
class MyService : Service() {
val listenerList = RemoteCallbackList<IMessageCallback>()//用来管理AIDL接口
override fun onCreate() {
super.onCreate()
val task = object : TimerTask() {
override fun run() {
val size = listenerList.beginBroadcast()//开始遍历集合
for (i in 0..size - 1) {
val callback = listenerList.getBroadcastItem(i)
callback.message("现在时间是: ${Date().toString()}")//给每一个注册用户发送当前时间
}
listenerList.finishBroadcast()//结束遍历集合
}
}
Timer().schedule(task, 5000, 5000)//五秒钟之后每隔五秒钟运行一次
}
override fun onBind(intent: Intent?): IBinder = object : IMessageHandler.Stub() {
override fun register(callback: IMessageCallback?) {
listenerList.register(callback)
}
override fun unregister(callback: IMessageCallback?) {
listenerList.unregister(callback)
}
}
}
class MainActivity : AppCompatActivity() {
var service: IMessageHandler? = null
val handler = Handler() //用于线程转换
val message = object : IMessageCallback.Stub() {
override fun message(message: String?) {
handler.post { -> //消息接收线程为子线程,这里需要使用handler进行线程切换
Toast.makeText(this@MainActivity, message, Toast.LENGTH_SHORT).show()
}
}
}
val conn = object : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName?) {
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
var myService = IMessageHandler.Stub.asInterface(service)
if (myService != null) { //一旦连接服务器成功就向服务器注册回调
myService.register(message)
}
this@MainActivity.service = myService
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = Intent("chenxiaomo")
bindService(intent, conn, Context.BIND_AUTO_CREATE)
}
override fun onDestroy() {
super.onDestroy()
service?.unregister(message) //取消注册
unbindService(conn) //断开与服务连接
}
}
需要注意的是,在上述操作中客户端接受到消息后,采用了Handler进行线程切换。
为什么要使用handler?能不能不使用Handler?
我们来看一下上面这个例子的服务端,我们使用了TimerTask来进行定时操作,很明显,这里的操作是在线程池中进行,那么客户端中的回调也是理所当然的运行在子线程中。假如我们把服务端代码换成这个样子
class MyService : Service() {
val listenerList = RemoteCallbackList<IMessageCallback>()//用来管理AIDL接口
override fun onBind(intent: Intent?): IBinder = object : IMessageHandler.Stub() {
override fun register(callback: IMessageCallback?) {
listenerList.register(callback)
callback?.message("hello")
}
override fun unregister(callback: IMessageCallback?) {
listenerList.unregister(callback)
}
}
}
也就是改成当连接成功时发送消息给客户端,这里很明显发送方法运行在UI线程,所以客户端不需要handler就能够处理消息。
所以分析可得当我们不知道对方的运行环境并且还要操作UI时,最好使用Handler进行线程切换。
由于AIDL的连接需要依托Android中的服务机制,而服务机制却又是相当的不稳定,用户在设置中强行关闭服务,或者某些流氓软件比如某度安全卫士也会关闭一些服务。所以我们应该怎么在Binder死亡的时候重新唤起它呢?
这里我们需要一个回调接口IBinder.DeathRecipient,这是Android提供的一种服务死亡回调接口,我们需要实现这个接口,并在里面实现关闭死亡监听,然后重新连接服务。
下面是完整代码
class MainActivity : AppCompatActivity() {
var service: IMessageHandler? = null
val handler = Handler()
val message = object : IMessageCallback.Stub() {
override fun message(message: String?) {
handler.post { ->
Toast.makeText(this@MainActivity, message, Toast.LENGTH_SHORT).show()
}
}
}
val deathRecipient = object : IBinder.DeathRecipient {
override fun binderDied() {
val service = this@MainActivity.service
if (service != null) {
service.asBinder().unlinkToDeath(this, 0)
//断开已过期服务的死亡监听
this@MainActivity.service = null
//置空已过期的服务
bindService()//重新连接服务
}
}
}
val conn = object : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName?) {
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
var myService = IMessageHandler.Stub.asInterface(service)
if (myService != null) {
service!!.linkToDeath(deathRecipient, 0)
//连接成功后给服务设置死亡监听
myService.register(message)
}
this@MainActivity.service = myService
}
}
private fun bindService() {
val intent = Intent("chenxiaomo")
bindService(intent, conn, Context.BIND_AUTO_CREATE)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bindService()
}
override fun onDestroy() {
super.onDestroy()
service?.unregister(message)
unbindService(conn)
}
}
现在我们关闭服务看看客户端能不能正常的吐司呢?