简介
无意中发现的一款简单易用的任务执行器,支持多个任务流式并且可跨线程执行,简单粗暴,可以完全让你抛弃让人讨厌的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
922

被折叠的 条评论
为什么被折叠?



