背景
之前写了一篇关于如何自定义APngDrawable的文章,当时通过提交任务到线程池来解码apng 文件。其中帧播放的逻辑控制也过于复杂,需要不断的计算帧延时刷新。并且APngDrawable在播放apng文件的过程中,解码线程会经常的发生挂起。为了充分的利用线程,避免挂起线程,并且简化帧播放逻辑。所以我们考虑使用协程来解决这些问题。
协程
协程可以挂起执行,这里的挂起执行与线程的挂起不同。它没有阻塞线程,而是记录当前执行的位置。当异步执行结束后从记录的执行位置继续执行,挂起前后的执行线程有可能不同。利用协程的非阻塞特性可以有效优化apng文件的解码过程。
协程在解码过程中的使用
启动播放apng的过程就是启动协程任务的过程。协程的协程体中进行循环播放控制,帧解码控制,帧渲染控制。下面看下具体的代码:
playJob = launch(Dispatchers.IO) {
/**
* for decode the apng file.
*/
var aPngDecoder: APngDecoder? = null
frameBuffer = FrameBuffer(columns, rows)
try {
// send start event.
sendEvent(PlayEvent.START)
//Loop playback.
repeat(plays) { playCounts ->
log { "play start play count : $playCounts" }
if (playCounts > 0) {
//send repeat event.
sendEvent(PlayEvent.REPEAT)
}
//init apng decoder and frame buffer.
if (aPngDecoder == null) {
aPngDecoder = APngDecoder(streamCreator.invoke())
frameBuffer!!.reset()
}
aPngDecoder?.let { decoder ->
log { "decode start decoder ${decoder.hashCode()} skipFrameCount $skipFram