供其他人使用,这是我最终得到的实现。
interface Executor {
fun onMainThread(function: () -> Unit)
fun onWorkerThread(function: suspend () -> Unit) : Job
}
object ExecutorImpl : Executor {
override fun onMainThread(function: () -> Unit) {
launch(UI) { function.invoke() }
}
override fun onWorkerThread(function: suspend () -> Unit): Job {
return async(CommonPool) { function.invoke() }
}
}
我在构造函数中注入Executor
并使用 kotlins 委托来避免样板代码:
class SomeInteractor @Inject constructor(private val executor: Executor)
: Interactor, Executor by executor {
...
}
现在可以Executor
互换使用 -methods:
override fun getSomethingAsync(listener: ResultListener?) {
job = onWorkerThread {
val result = repository.getResult().awaitResult()
onMainThread {
when (result) {
is Result.Ok -> listener?.onResult(result.getOrDefault(emptyList())) :? job.cancel()
// Any HTTP error
is Result.Error -> listener?.onHttpError(result.exception) :? job.cancel()
// Exception while request invocation
is Result.Exception -> listener?.onException(result.exception) :? job.cancel()
}
}
}
}
在我的测试中,我Executor
用这个切换了实现。
对于单元测试:
/**
* Testdouble of [Executor] for use in unit tests. Runs the code sequentially without invoking other threads
* and wraps the code in a [runBlocking] coroutine.
*/
object TestExecutor : Executor {
override fun onMainThread(function: () -> Unit) {
Timber.d("Invoking function on main thread")
function()
}
override fun onWorkerThread(function: suspend () -> Unit): Job {
runBlocking {
Timber.d("Invoking function on worker thread")
function()
}
return mock<Job>()
}
}
对于仪器测试:
/**
* Testdouble of [Executor] for use in instrumentations tests. Runs the code on the UI thread.
*/
object AndroidTestExecutor : Executor {
override fun onMainThread(function: () -> Unit) {
Timber.d("Invoking function on worker thread")
function()
}
override fun onWorkerThread(function: suspend () -> Unit): Job {
return launch(UI) {
Timber.d("Invoking function on worker thread")
function()
}
}
}