前言
项目开发中可能会出现需要多个同步任务串行执行,或者多个异步任务都执行完毕再执行下一步的
其实如果用kotlin的协程的话,可以很方便的完成,但如果不想用kt写或者引入协程库的话,就可以用下面两个工具类
正文
同步串行执行任务,使用链表结构
import com.lt.androidkj.utils.mlistener.EmptyListener
import com.lt.androidkj.utils.mlistener.FunctionFlowBeanListener
/**
* creator: lt 2019/11/26--10:40 [email protected]
* effect : 方法顺序运作工具类,使用链表数据结构
* warning:
*/
class FunctionFlow {
private var first: LinkedBean? = null//头结点
private var last: LinkedBean? = null//尾结点
private var finishListener: EmptyListener? = null//全部事件结束的回调
/**
* 顺序的添加任务
* @param id 正常情况下没什么用,但是next(n)的时候跳转到指定的id上
* @param function 执行的任务,回调里有个FunctionFlowBean类型的参数,调用他的invoke()可以执行后面的方法
*/
fun add(id: Int = 0, function: FunctionFlowBeanListener): FunctionFlow {
//第一次添加
if (first == null) {
first = LinkedBean(function, id)
last = first
return this
}
//以后再添加
val functionFlowBean = LinkedBean(function, id)
last!!.next = functionFlowBean
last = functionFlowBean
return this
}
/**
* 开始顺序执行所有任务,后面的任务完成后调用.invoke()即可开始下一个任务
* @param finishListener 全部任务完成后触发,可以不传
*/
@JvmOverloads
fun start(finishListener: EmptyListener? = null) {
val first = first ?: return
this.finishListener = finishListener
//设置尾结点,保证链式调用中,参数不为空
val noFunctionFlowBean = LinkedBean({}, -1)
last!!.next = noFunctionFlowBean
last = noFunctionFlowBean
//开始第一个任务
first.function(first.next!!)
}
/**
* 链表bean
*/
inner class LinkedBean(
val function: FunctionFlowBeanListener,
val id: Int,
var next: LinkedBean? = null
) {
/**
* 开始下一个任务
* @param skip -1表示下一个任务,大于0表示跳到id为n的任务
*/
@JvmOverloads
fun ok(skip: Int = -1) {
if (skip < 0) {
//执行下一个任务
val next = next
if (next == null) {
finishListener?.invoke()
return
}
function(next)
} else {
//跳到id为n的任务
var next: LinkedBean? = this
while (true) {
if (next == null) {//判断如果后续没有方法,则走finish
finishListener?.invoke()
return
}
if (next.id == skip) {//如果下一个任务的id和指定的id相同,则调用下一个方法
next.function(next.next!!)
return
}
next = next.next//如果上面两个条件都不符合,则判断下一个任务
}
}
}
}
}
typealias EmptyListener = () -> Unit
typealias FunctionFlowBeanListener = (FunctionFlow.LinkedBean) -> Unit
typealias FunctionStartsBeanListener = (FunctionStarts.EndBean) -> Unit
使用方式:
异步并行执行任务,也是使用的链表结构:
import com.lt.androidkj.utils.ThreadPool.ThreadType.*
import com.lt.androidkj.utils.mlistener.EmptyListener
import com.lt.androidkj.utils.mlistener.FunctionStartsBeanListener
/**
* creator: lt 2019/12/23--17:15 [email protected]
* effect : 同时执行所有任务,全部执行完成后调用完成的回调,可以指定线程,默认子线程
* warning:
*/
class FunctionStarts {
private val map = LinkedHashMap<EndBean, ThreadPool.ThreadType>()
/**
* 添加任务,并指定该任务所运行的线程模式
*/
fun add(type: ThreadPool.ThreadType = CACHE, function: FunctionStartsBeanListener): FunctionStarts {
map[EndBean(function)] = type
return this
}
/**
* 开始所有任务,并在全部完成后执行回调,且不保证运行在哪个线程中
*/
fun start(finishListener: EmptyListener) {
map.forEach { (bean, type) ->
when (type) {
SINGLE -> ThreadPool::submitToSingleThreadPool
CACHE -> ThreadPool::submitToCacheThreadPool
FIXED -> ThreadPool::submitToTimeThreadPoolNoTime
MAIN -> ::post
}{
bean.endListener = {
synchronized(this@FunctionStarts) {
map.remove(bean)
if (map.size == 0)
finishListener()
}
}
bean.run(bean)
}
}
}
/**
* 调用该类的end方法,表示任务已经执行完毕
* @param run 提交的任务
*/
class EndBean(val run: FunctionStartsBeanListener) {
//任务结束的回调
var endListener: EmptyListener? = null
/**
* 表示任务已经执行完毕
*/
fun ok() {
endListener?.invoke()
}
}
}
/**
* 线程类型
*/
enum class ThreadType {
/**
* 单例线程,选择这种方式会按照启动的先后顺序串行执行
*/
SINGLE,
/**
* 缓存线程池,选择这种方式会和其他任务并行执行,且无上限
*/
CACHE,
/**
* 固定长度的线程池,达到设定的线程数量后,后面的任务等待空闲线程执行完毕后再执行
*/
FIXED,
/**
* 跑在主线程中
*/
MAIN
}
使用方式:
而且还能联合使用来应对复杂需求,比如
先按照顺序弹两个弹窗(关闭前一个在打开下面的),然后请求三个异步接口(但要求第二个和第三个要按顺序执行),接口全部成功后在按照顺序弹两个弹窗
FunctionFlow()
.add {
showSelectPhotoDialog(1) { arr ->
it.ok()
}
}
.add {
showSelectPhotoDialog(1) { arr ->
it.ok()
}
}
.add {
//执行异步网络请求
FunctionStarts()
.add {
http1 {
it.ok()
}
}
.add(ThreadPool.ThreadType.SINGLE) {
http2 {
it.ok()
}
}
.add(ThreadPool.ThreadType.SINGLE) {
http3 {
it.ok()
}
}
.start {
print("异步接口执行完毕")
it.ok()
}
}
.add {
showSelectPhotoDialog(1) { arr ->
it.ok()
}
}
.add {
showSelectPhotoDialog(1) { arr ->
it.ok()
}
}
.start {
print("任务全部执行完成")
}