AAC 的 Lifecycle 结合 Kotlin Coroutines 进行使用

栏目: Android · 发布时间: 5年前

内容简介:目前,AAC(Android Architecture Components简称) 已经是 Android Jetpack 的一部分。Lifecycle 是 AAC 其中的一个组件,Lifecycle 能够管理 Activity 和 Fragment 的生命周期。Lifecycle 可以构建感知生命周期的组件 —— 这些组件根据 Activity、Fragment 的当前生命周期状态自动调整其行为。并且,LiveData 与 ViewModel 的 lifecycle 也依赖于 Lifecycle。首先,
AAC 的 Lifecycle 结合 Kotlin Coroutines 进行使用

一. Lifecycle

目前,AAC(Android Architecture Components简称) 已经是 Android Jetpack 的一部分。Lifecycle 是 AAC 其中的一个组件,Lifecycle 能够管理 Activity 和 Fragment 的生命周期。

Lifecycle 可以构建感知生命周期的组件 —— 这些组件根据 Activity、Fragment 的当前生命周期状态自动调整其行为。并且,LiveData 与 ViewModel 的 lifecycle 也依赖于 Lifecycle。

二. 创建 LifecycleObserver 的实现类

首先,创建一个 LifecycleObserver 接口的实现类 LifecycleCoroutineListener,在 Activity/Fragment 某个生命周期事件上(默认为Lifecycle.Event.ON_DESTROY),协程会调用取消的方法。

open class LifecycleCoroutineListener(private val job: Job,
                                 private val cancelEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY) : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun pause() = handleEvent(Lifecycle.Event.ON_PAUSE)

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stop() = handleEvent(Lifecycle.Event.ON_STOP)

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun destroy() = handleEvent(Lifecycle.Event.ON_DESTROY)

    private fun handleEvent(e: Lifecycle.Event) {

        if (e == cancelEvent && !job.isCancelled) {
            job.cancel()
        }
    }
}
复制代码

三. 列举使用场景

3.1 使用协程并绑定生命周期

创建 GlobalScope 的扩展函数 asyncWithLifecycle,它使用 async 创建一个 deferred 对象,并使用 lifecycleOwner 的 lifecycle 去绑定 LifecycleCoroutineListener。

fun <T> GlobalScope.asyncWithLifecycle(lifecycleOwner: LifecycleOwner,
                                       context: CoroutineContext = EmptyCoroutineContext,
                                       start: CoroutineStart = CoroutineStart.DEFAULT,
                                       block: suspend CoroutineScope.() -> T): Deferred<T> {

    val deferred = GlobalScope.async(context, start) {

        block()
    }

    lifecycleOwner.lifecycle.addObserver(LifecycleCoroutineListener(deferred))

    return deferred
}
复制代码

可以采用如下的方式进行使用,如果需要显示toast的话,必须使用 Dispatchers.Main 这样才能在主线程显示 toast:

GlobalScope.asyncWithLifecycle(this,Dispatchers.Main) {

            delay(1000)

            Toast.makeText(mContext,"hi, this must use 'Dispatchers.Main'",Toast.LENGTH_SHORT).show()
        }
复制代码

使用 Dispatchers.Main 时,需要在 build.gradle 中添加

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1'
复制代码

3.2 协程的block绑定生命周期

创建 GlobalScope 的扩展函数 bindWithLifecycle,它的协程 block 在调用时绑定生命周期。

fun <T> GlobalScope.bindWithLifecycle(lifecycleOwner: LifecycleOwner,
                                      block: CoroutineScope.() -> Deferred<T>): Deferred<T> {

    val deferred = block.invoke(this)

    lifecycleOwner.lifecycle.addObserver(LifecycleCoroutineListener(deferred))

    return deferred
}
复制代码

可以采用如下的方式进行使用:

GlobalScope.bindWithLifecycle(this) {

            GlobalScope.async(Dispatchers.Main) {

                val deferred1 = async(Dispatchers.Default) {

                    delay(1000)
                    1
                }

                val deferred2 = async(Dispatchers.Default) {

                    delay(1500)
                    2
                }

                val result = deferred1.await() + deferred2.await()

                Toast.makeText(mContext,"the result is $result",Toast.LENGTH_SHORT).show()
            }
        }
复制代码

3.3 then

创建 Deferred 的扩展函数 then,它会创建一个协程并运行在 UI 线程上:

infix fun <T> Deferred<T>.then(block: (T) -> Unit): Job {

    return GlobalScope.launch(context = Dispatchers.Main) {

        block(this@then.await())
    }
}
复制代码

由于它使用了 infix ,并结合 asyncWithLifecycle 一起使用:

GlobalScope.asyncWithLifecycle(this,Dispatchers.IO) {

            delay(5000) // 模拟耗时的网络请求
            1
        } then {

            Toast.makeText(mContext,"the result is $it",Toast.LENGTH_SHORT).show()
        }
复制代码

asyncWithLifecycle 使用了 Dispatchers.IO 来模拟一些耗时的网络请求。在实际开发中也可以这样使用,网络请求的结果使用 then 进行展示。

3.4 thenAsync

thenAsync 类似于 then,区别在于返回的对象不同。

infix fun <T, R> Deferred<T>.thenAsync(block: (T) -> R): Deferred<R> {

    return GlobalScope.async(context = Dispatchers.Main) {

        block(this@thenAsync.await())
    }
}
复制代码

thenAsync 返回的是 Deferred 对象,因此可以使用如下的链式调用:

GlobalScope.asyncWithLifecycle(this, Dispatchers.IO) {

            delay(5000) // 模拟耗时的网络请求
            1
        } thenAsync {

            it + 2
        } then {

            Toast.makeText(mContext,"the result is $it", Toast.LENGTH_SHORT).show()
        }
复制代码

3.5 awaitOrNull

创建 Deferred 的扩展函数 awaitOrNull,它参考了 Java 的 Future 的超时方法。如果遇到超时或者异常,则返回null。

suspend fun <T> Deferred<T>.awaitOrNull(timeout: Long = 0L): T? {
    return try {
        if (timeout > 0) {

            withTimeout(timeout) {

                this@awaitOrNull.await()
            }

        } else {

            this.await()
        }
    } catch (e: Exception) {

        Log.e("Deferred", e.message)
        null
    }
}
复制代码

下面的例子中,deferred 会在 5秒才有返回值,但是deferred 使用了awaitOrNull(),它的超时时间是4秒,因此 result 的值为 null。

val deferred = GlobalScope.asyncWithLifecycle(this, Dispatchers.IO) {

            delay(5000) // 模拟耗时的网络请求
            1
        }

        GlobalScope.asyncWithLifecycle(this,Dispatchers.Main) {

            val result = deferred.awaitOrNull(4000)

            Toast.makeText(mContext,"the result is $result", Toast.LENGTH_SHORT).show()
        }
复制代码

如果把超时时间设置大于5秒的话,result 会返回正确的值。

3.6 任意 job 绑定到生命周期

还记得最初的 LifecycleCoroutineListener 嘛?它使用了 open ,因此任意创建的协程都可以使用它来绑定生命周期。


以上所述就是小编给大家介绍的《AAC 的 Lifecycle 结合 Kotlin Coroutines 进行使用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Clean Code

Clean Code

Robert C. Martin / Prentice Hall / 2008-8-11 / USD 49.99

Even bad code can function. But if code isn’t clean, it can bring a development organization to its knees. Every year, countless hours and significant resources are lost because of poorly written code......一起来看看 《Clean Code》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具