美文网首页
Android 多个后台任务和 UI 任务串行执行的链式调用设计

Android 多个后台任务和 UI 任务串行执行的链式调用设计

作者: 雁过留声_泪落无痕 | 来源:发表于2019-09-30 15:01 被阅读0次

版本1

调用方式:

private fun testAsyncChain() {
    AsyncChain().next(AsyncChain.UI_THREAD_TYPE) {
        Toast.makeText(this@MainActivity, "begin", Toast.LENGTH_SHORT).show()
    }.next(AsyncChain.WORK_THREAD_TYPE) {
        Thread.sleep(1000L)
        1
    }.next(AsyncChain.UI_THREAD_TYPE) {
        Toast.makeText(this@MainActivity, "middle", Toast.LENGTH_SHORT).show()
        (it as Int) + 2
    }.next(AsyncChain.WORK_THREAD_TYPE) {
        Thread.sleep(3000L)
        (it as Int) + 3
    }.next(AsyncChain.UI_THREAD_TYPE) {
        Toast.makeText(this@MainActivity, "end, result: $it", Toast.LENGTH_SHORT).show()
    }.start()
}

实现代码:

package com.example.helloworld.tools

import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.properties.Delegates

class AsyncChain {

    companion object {
        const val UI_THREAD_TYPE = 0
        const val WORK_THREAD_TYPE = 1
    }

    private class Task(val threadType: Int, val action: (Any?) -> Any?)

    private val lock = Object()
    private var cancelled = false
    private var lastResult: Any? = null
    private val tasks = Collections.synchronizedList(LinkedList<Task>())
    private var isExecuting: AtomicBoolean = AtomicBoolean(false)
    private val thread = HandlerThread("AsyncChain")
    private var workHandler by Delegates.notNull<Handler>()
    private val uiHandler = Handler(Looper.getMainLooper())

    fun next(threadType: Int, action: (Any?) -> Any?): AsyncChain {
        if (isExecuting.get()) {
            throw IllegalStateException("tasks are running already!")
        }

        tasks.add(Task(threadType, action))
        return this
    }

    fun start() {
        execute()
    }

    fun cancel() {
        cancelled = true
    }

    private fun execute() {
        if (isExecuting.getAndSet(true)) {
            throw IllegalStateException("tasks are running already!")
        }

        thread.start()
        workHandler = Handler(thread.looper)
        Thread() {
            try {
                for (task in tasks) {
                    if (cancelled) {
                        break
                    }

                    when {
                        task.threadType == UI_THREAD_TYPE -> uiHandler.post {
                            lastResult = task.action(lastResult)
                            synchronized(lock) {
                                lock.notify()
                            }
                        }
                        task.threadType == WORK_THREAD_TYPE -> workHandler.post {
                            lastResult = task.action(lastResult)
                            synchronized(lock) {
                                lock.notify()
                            }
                        }
                        else -> throw IllegalArgumentException("unknown thread type: ${task.threadType}")
                    }
                    synchronized(lock) {
                        lock.wait()
                    }
                }
            } finally {
                thread.quit()
            }
        }.start()
    }

}

RxJava直接就能实现(相比之下,代码会稍微多点):

private fun testRxJava() {
    val executor = Executors.newSingleThreadExecutor()
    val scheduler = Schedulers.from(executor)
    Observable
        .create<Int> { emitter ->
            Toast.makeText(this@MainActivity, "begin", Toast.LENGTH_SHORT).show()
            emitter.onNext(0)
            emitter.onComplete()
        }
        .subscribeOn(AndroidSchedulers.mainThread())
        .observeOn(scheduler)
        .map {
            Log.v(TAG, "thread: ${Thread.currentThread().name}")
            Thread.sleep(1000L)
            1
        }
        .observeOn(AndroidSchedulers.mainThread())
        .map {
            Toast.makeText(this@MainActivity, "middle", Toast.LENGTH_SHORT).show()
            Log.v(TAG, "thread: ${Thread.currentThread().name}")
            it + 2
        }
        .observeOn(scheduler)
        .map {
            Log.v(TAG, "thread: ${Thread.currentThread().name}")
            Thread.sleep(3000L)
            it + 3
        }
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe() {
            Log.v(TAG, "thread: ${Thread.currentThread().name}")
            Toast.makeText(this@MainActivity, "end, result: $it", Toast.LENGTH_SHORT).show()
        }
}


版本2

调用方式:

private fun testAsyncChain() {
    AsyncChain().next(true, AsyncChain.UI_THREAD_TYPE) { param ->
        Toast.makeText(this@MainActivity, "begin", Toast.LENGTH_SHORT).show()
        AlertDialog
            .Builder(this)
            .setTitle("Test")
            .setMessage("waiting! confirm to run next task.")
            .setPositiveButton("confirm") { _, _ ->
                param.confirm()
            }
            .setNegativeButton("cancel") { _, _ ->
                param.cancel()
            }
            .show()
    }.next(AsyncChain.WORK_THREAD_TYPE) {
        Thread.sleep(1000L)
        1
    }.next(AsyncChain.UI_THREAD_TYPE) {
        Toast.makeText(this@MainActivity, "middle", Toast.LENGTH_SHORT).show()
        (it.lastResult as Int) + 2
    }.next(AsyncChain.WORK_THREAD_TYPE) {
        Thread.sleep(3000L)
        (it.lastResult as Int) + 3
    }.next(AsyncChain.UI_THREAD_TYPE) {
        Toast.makeText(
            this@MainActivity,
            "end, last result: ${it.lastResult}",
            Toast.LENGTH_SHORT
        ).show()
    }.start()
}

实现代码:

package com.example.helloworld.tools

import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.properties.Delegates

class AsyncChain {

    companion object {
        const val UI_THREAD_TYPE = 0
        const val WORK_THREAD_TYPE = 1
    }

    private class Task(val waitToConfirm: Boolean, val threadType: Int, val action: (Param) -> Any?)

    class Param(
        var waitToConfirm: Boolean,
        var lastResult: Any?,
        private val chain: AsyncChain,
        private val lock: Object
    ) {
        fun confirm() {
            if (waitToConfirm) {
                synchronized(lock) {
                    lock.notify()
                }
            } else {
                // no need to call confirm()
            }
        }

        fun cancel() {
            chain.cancel()
            if (waitToConfirm) {
                synchronized(lock) {
                    lock.notify()
                }
            }
        }
    }

    private val lock = Object()
    private var param = Param(false, null, this, lock)
    private var cancelled = false
    private val tasks = Collections.synchronizedList(LinkedList<Task>())
    private var isExecuting: AtomicBoolean = AtomicBoolean(false)
    private val thread = HandlerThread("AsyncChain")
    private var workHandler by Delegates.notNull<Handler>()
    private val uiHandler = Handler(Looper.getMainLooper())

    fun next(threadType: Int, action: (Param) -> Any?): AsyncChain {
        return next(false, threadType, action)
    }

    fun next(waitToConfirm: Boolean, threadType: Int, action: (Param) -> Any?): AsyncChain {
        if (isExecuting.get()) {
            throw IllegalStateException("tasks are running already!")
        }

        tasks.add(Task(waitToConfirm, threadType, action))
        return this
    }

    fun start() {
        execute()
    }

    fun cancel() {
        cancelled = true
    }

    private fun doJob(task: Task) {
        param.waitToConfirm = task.waitToConfirm
        param.lastResult = task.action(param)
        if (!task.waitToConfirm) {
            synchronized(lock) {
                lock.notify()
            }
        }
    }

    private fun execute() {
        if (isExecuting.getAndSet(true)) {
            throw IllegalStateException("tasks are running already!")
        }

        thread.start()
        workHandler = Handler(thread.looper)
        Thread() {
            try {
                for (task in tasks) {
                    if (cancelled) {
                        break
                    }

                    when {
                        task.threadType == UI_THREAD_TYPE -> uiHandler.post {
                            doJob(task)
                        }
                        task.threadType == WORK_THREAD_TYPE -> workHandler.post {
                            doJob(task)
                        }
                        else -> throw IllegalArgumentException("unknown thread type: ${task.threadType}")
                    }
                    synchronized(lock) {
                        lock.wait()
                    }
                }
            } finally {
                thread.quit()
            }
        }.start()
    }

}


leehong大神在13年实现了一个版本:Android 异步链式调用设计

相关文章

网友评论

      本文标题:Android 多个后台任务和 UI 任务串行执行的链式调用设计

      本文链接:https://www.haomeiwen.com/subject/wqzcpctx.html