AIDL进阶

AIDL进阶

标签(空格分隔): android
作者:陈小默


1,基本使用

至于AIDL的基本使用方法这里就不再介绍,可以参看博文Android Studio中使用Kotlin语言实现AIDL通信[图文] 。这篇博文通过一个简单的接口实现回复客户端发送的字符串功能来介绍了AIDL工程的创建。

2,接口回调管理

按照我们标题1中的基本示例仅仅是客户端主动调用服务端的方法,可是我们如果要实现服务端主动联系客户端应该怎么办?
下面我们使用一个服务端每5秒钟向客户端发送一条消息的例子来展示如何设置回调。

第一步:创建AIDL文件

// 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) //断开与服务连接
    }
}

3,耗时操作的处理

需要注意的是,在上述操作中客户端接受到消息后,采用了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进行线程切换。

4,Binder死亡处理

由于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)
    }
}

现在我们关闭服务看看客户端能不能正常的吐司呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值