SimpleTaskExecutor一款简单易用的任务执行器

简介

无意中发现的一款简单易用的任务执行器,支持多个任务流式并且可跨线程执行,简单粗暴,可以完全让你抛弃让人讨厌的Thread+Handler组合,对于有需要异步线程转UI线程的同学应该是一个不错的选择。

用法

核心API

API很简单实际是6个我这里列出了5个,另外一个感觉不会用到哈哈(个人见解,勿喷)。

接口说明
SimpleTaskExecutor.create()创建一个TaskFlow,执行器内所有的任务实际都是通过TaskFlow执行的
TaskFlow.planTaskSync(block:(task:Task)-> Unit)添加一个任务使其同步执行,在启动线程内执行,参数task是执行任务信息,可以在期内保存,在下个任务执行时会将本次任务执行结果传入
TaskFlow.planTaskAsync(block:(task:Task)-> Unit)添加一个任务使其异步执行,在执行器内的异步线程内运行
TaskFlow.planTaskInMain(block:(task:Task)-> Unit)添加一个任务使其在主线程中运行
TaskFlow.execute()开始执行事件流,会根据添加顺序依次执行添加的任务

使用

先上代码

    Thread {
        SimpleTaskExecutor.create()
            .planTaskSync {
                it.result = 10
                Log.d("MainActivity","1.work in thread:${Thread.currentThread().name}")
            }
            .planTaskAsync {
                it.result = if (it.result != null) (it.result as Int) + 10 else -100
                   Log.d("MainActivity","2.work in thread:${Thread.currentThread().name}")
                }
            .planTaskInMain {
                findViewById<TextView>(R.id.mTv).text = "" + it.result.toString()
                Log.d("MainActivity","3.work in thread:${Thread.currentThread().name}")
            }.execute()
            Log.d("MainActivity","${Thread.currentThread().name} end")
    }.start()

使用很简单,作者这里是在线程内通过SimpleTaskExecutor执行了三个任务,三个任务都是在一个TaskFlow内运行的,所以会依次执行。
第一个任务是同步的,也就是在新自己创建的Thread里面运行的,并且将10保存到了task内。
第二个任务是异步的会在SimpleTaskExecutor内的异步执行器内运行,并且给task中的结果+10。
第三个任务是在主线程内运行的所以可以直接更新UI将结果显示。

实现原理

因为SimpleTaskExecutor内部还是通过TaskFlow执行任务的,因此我们就直接看TaskFlow即可,源码如下:

class TaskFlow(var id:Long = System.currentTimeMillis()) {

    private var flow = ArrayList<Task>()
    private var result:Task = Task {  }

    fun planTaskAsync(block:(task:Task)-> Unit):TaskFlow{
        planTask(ExecutorType.TYPE_ASYNC,block)
        return this
    }

    fun planTaskSync(block:(task:Task)-> Unit):TaskFlow{
        planTask(ExecutorType.TYPE_SYNC,block)
        return this
    }

    fun planTaskInMain(block:(task:Task)-> Unit):TaskFlow{
        planTask(ExecutorType.TYPE_IN_MAIN,block)
        return this
    }

    fun planTask(type:ExecutorType,block:(task:Task)-> Unit):TaskFlow{
        flow.add(Task(type,block))
        return this
    }

   fun execute() {
       try {
           LogPrint.debug("TaskFlow-$id execute begin")
           var begin = System.currentTimeMillis()
          if(Looper.myLooper() == null){
              Looper.prepare()
              var looper = Looper.myLooper()!!
              Handler(looper).apply {
                  post {
                      doExeTask(0, this){
                          looper.quit()
                          LogPrint.debug("TaskFlow-$id execute end,  time consuming :${System.currentTimeMillis() - begin}ms")
                      }
                  }
              }
              Looper.loop()
           }else {
              doExeTask(0,  Handler(Looper.myLooper()!!)){
                  LogPrint.debug("TaskFlow-$id execute end,  time consuming :${System.currentTimeMillis() - begin}ms")
              }
          }
       }catch (e:Exception){
           LogPrint.error("TaskFlow-$id execute error :",e)
       }
   }

    private fun doExeTask(index:Int,synThreadWorker: Handler,endCbk:()->Unit = {}){
        if(flow.size<=index) {
            endCbk()
            return
        }
        var begin = System.currentTimeMillis()
        var it = flow[index]
        result.type = it.type
        when(it.type){
            ExecutorType.TYPE_ASYNC -> AsyncThreadWorker.get().execute{
                it.execute(result){
                    LogPrint.debug("TaskFlow-$id Task${index+1} execute end,  time consuming :${System.currentTimeMillis() - begin}ms")
                    doExeTask(index+1,synThreadWorker,endCbk)
                }
            }
            ExecutorType.TYPE_IN_MAIN -> MainThreadWorker.get().execute{
                it.execute(result){
                    LogPrint.debug("TaskFlow-$id Task${index+1} execute end,  time consuming :${System.currentTimeMillis() - begin}ms")
                    doExeTask(index+1,synThreadWorker,endCbk)
                }
            }
            ExecutorType.TYPE_SYNC -> synThreadWorker.post {
                it.execute(result){
                    LogPrint.debug("TaskFlow-$id Task${index+1} execute end,  time consuming :${System.currentTimeMillis() - begin}ms")
                    doExeTask(index+1,synThreadWorker,endCbk)
                }
            }
        }
    }
}

可以看到内部有一个名为flow的ArrayList<Task>,这个flow可以看出来就是用来保存我们添加进来任务的。

接下来看planTask*函数,这些函数都只有一个函数作为参数,在planTask*函数内创建了一个Task对象,并将外面传进来参数传到了task内,并额外添加了执行器类型,看到这里添加任务就结束了。

我们继续看执行函数execute(),首先创建了一个当前线程的执行器Handler,E…,如果当前线程没有Looper那么这样会阻塞当前线程,如果要在当前线程执行的话,貌似也没什么好的办法。

继续看,之后会走到doExeTask函数,这个函数是通过递归的方式依次执行多个任务的,在execute调用doExeTask时传入了三个参数,分别是index(当前执行任务的索引),synThreadWorker(当前线程的任务执行器),endCbk(所有任务执行结束的回调)。

在doExeTask内使用了一个名为result的Task对象,这个对象是TaskFlow中的一个全局变量,作用是贯穿所有任务,传递当前执行任务的信息和执行结果。

接下来就是根据具体执行任务的执行器类型匹配对应的执行器,然后调用taskd的execute()函数,这个函数有两个参数,一个参数传入的是一个Task对象,这个task对象就是我们上面说到的result对象,还有一个是任务执行结束之后的回调,在这个回调中index+1并递归调用doExeTask直到任务结束。

看着到这里基本上整个执行器的核心逻辑就看的差不多了,剩下的就是Task类和几个执行器,这几个类都很简单,基本上看看都能懂,然后主要说明下AsyncThreadWorker类这个是异步任务执行器,看来下内部使用一个并发的线程池,只是作者没有对外公开设置线程数量的接口,在SimpleTaskExecutor初始化时直接传的是3,因此异步并发线程数量也就是3个了,应该后续还会再优化,毕竟还有很大优化空间,碰巧在这个项目刚提交一两天我就看到了这个项目,感觉很有意思,所以就拿来研究了下。

下面附上这个项目的地址,感兴趣的同学可以继续直接看看源码,目前这个项目没有maven也没有发布aar,所以要用的也只能导入源码,目测作者后续可能会发布maven,坐等发布,哈哈,废话就不多说了,至此该这个这个任务执行器就介绍完毕,感谢观看。

https://gitee.com/zlgspace/SimpleTaskExecutor

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值