手动实现kt(java)同步工作流和异步工作流

前言

项目开发中可能会出现需要多个同步任务串行执行,或者多个异步任务都执行完毕再执行下一步的

其实如果用kotlin的协程的话,可以很方便的完成,但如果不想用kt写或者引入协程库的话,就可以用下面两个工具类

正文

同步串行执行任务,使用链表结构

import com.lt.androidkj.utils.mlistener.EmptyListener
import com.lt.androidkj.utils.mlistener.FunctionFlowBeanListener

/**
 * creator: lt  2019/11/26--10:40    lt.dygzs@qq.com
 * 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    lt.dygzs@qq.com
 * 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
    }
::post实现方式如下
    val handler=Handler()
    fun post(listener:EmptyListener){
        handler.post(listener)
    }

其他的submitXXX都是提交到线程池,类似于如下
val singleThreadExecutor = Executors.newSingleThreadExecutor()//可以自己搜索如何创建或自定义线程池
    fun submitToSingleThreadPool(runnable: EmptyListener): Future<*> =
        singleThreadExecutor.submit(runnable)

使用方式:

而且还能联合使用来应对复杂需求,比如

先按照顺序弹两个弹窗(关闭前一个在打开下面的),然后请求三个异步接口(但要求第二个和第三个要按顺序执行),接口全部成功后在按照顺序弹两个弹窗

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("任务全部执行完成")
                }

对Kotlin或KMP感兴趣的同学可以进Q群 101786950

如果这篇文章对您有帮助的话

可以扫码请我喝瓶饮料或咖啡(如果对什么比较感兴趣可以在备注里写出来)

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值