基于Kotlin Channel实现任务队列

简介

基于kotlin coroutineChannel,实现的一个非阻塞式的任务队列,按先进先出的规则执行任务。

适用场景

适用于多个任务没有依赖关系,需要排队执行的情况。

比如:多个UI展示任务,需要排队一一展示的情况

  1. 弹框任务编排,例如,app首页有多个弹框(隐私弹框、权限弹框、更新弹框、运营弹框),需要按一定顺序排队展示,一个接一个展示,并且上一个主动关闭之后才能下一个。
  2. 直播间打赏礼物展示,打赏礼物动画需要一个一个展示的场景,动画展示的时间固定的。

引用

库在jitpack

1
maven { url 'https://jitpack.io' }
1
2
3
dependencies {
implementation 'com.github.yndongyong:taskqueue:v0.0.1'
}

特性

  1. 基于kotlin coroutine实现。
  2. First-In,First-out处理任务
  3. 支持指定task执行在主线程或是子线程

使用

  1. 创建任务队列管理类

    1
    mQueueManager = TaskQueueManager()
  2. 添加任务(有固定执行时间的)

    1
    2
    3
    mQueueManager.sendTask(Task(3000) {
    ToastUtils.showShort("btn click: $curCount ,counts")
    })
  3. 添加执行时间不固定的任务(展示一个弹框)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    mQueueManager.sendTask(Task {
    PopTip.show("弹框提示: $curCount", "关闭").noAutoDismiss()
    .setButton { popTip, v -> //点击“撤回”按钮回调
    //延迟1s展示下一个任务
    this@MainActivity.mViewBinding.btnShot.postDelayed(1000) {
    doNextTask()
    }
    false
    }
    })

执行时间不确定的任务,需要在任务执行完后主动调用 doNextTask() 方法去执行下一个task,否则消费者会一直挂起。

注意:还提供了一个全局单例TaskQueueManager.instance

分析

task定义

一类task是有固定执行时间的,比如展示一个toast,每次都是展示2s;一类task是没有固定的执行时间的,比如,app首页各种类型的弹框,权限弹框没有依赖信息,直接展示,如果不关闭的话,会一直展示,表示任务一直在执行中,只有当用户手动关闭弹框时,任务才结束。task可以执行在主线程,也可以执行在子线程处理耗时任务。执行完当前任务之后会执行下一个任务。

task支持指定要执行在主线程(默认),还是子线程,如果是执行时间固定的支持指定执行时间,默认是执行时间不固定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Created by yndongyong on 2022/10/11.
* @Description: 任务队列中的任务
* @property durationTimeMillis Long 任务执行的时间,0:表示任务执行时间不固定
* @property block [@kotlin.ExtensionFunctionType] Function1<Task, Unit> 执行块
* @constructor
*/
class Task(
override val durationTimeMillis: Long = 0,
override val callInMainThread: Boolean = true,
private val block: Task.() -> Unit
) : AbsTask() {

/**
* 执行任务
*/
override fun doTask() {
block.invoke(this)
}

}

队列处理

使用channel构造的生产者,消费者的多对一模型,消费者在消费task时,生产者被挂起。使用RENDEZVOUS类型的channel,没有缓冲区,同一时刻只能执行一个task,当执行taks,挂起send操作。执行task时切换到指定的Dispatchers.MAIN或者Dispatchers.IO协程上下文执行,如果task是执行时间不固定,使用Mutex挂起channelreceive操作所在的coroutine,当task执行完毕的恢复channelreceive操作所在的coroutine,同时send操作所在coroutine被恢复执行。