Skip to content

Instantly share code, notes, and snippets.

@bholota
Forked from LouisCAD/LifecycleCoroutines.kt
Created November 29, 2018 14:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bholota/a048a4ba2eb1a1ebd6c777e2cd30a4a1 to your computer and use it in GitHub Desktop.
Save bholota/a048a4ba2eb1a1ebd6c777e2cd30a4a1 to your computer and use it in GitHub Desktop.
CoroutineScope and Job integration with Lifecycle for Android. Meant to be used for your coroutines in lifecycle aware components. Ongoing PR: https://github.com/Kotlin/kotlinx.coroutines/pull/760
import android.arch.lifecycle.GenericLifecycleObserver
import android.arch.lifecycle.Lifecycle
import android.arch.lifecycle.Lifecycle.Event.ON_DESTROY
import android.arch.lifecycle.LifecycleOwner
import kotlinx.coroutines.experimental.CoroutineScope
import kotlinx.coroutines.experimental.Dispatchers
import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.android.Main
fun Lifecycle.createJob(cancelEvent: Lifecycle.Event = ON_DESTROY): Job {
if(cancelEvent in forbiddenCancelEvents) {
throw UnsupportedOperationException("$cancelEvent is forbidden for createJob(…).")
}
return Job().also { job ->
if (currentState == Lifecycle.State.DESTROYED) job.cancel()
else addObserver(object : GenericLifecycleObserver {
override fun onStateChanged(source: LifecycleOwner?, event: Lifecycle.Event) {
if (event == cancelEvent) {
removeObserver(this)
job.cancel()
}
}
})
}
}
private val forbiddenCancelEvents = arrayOf(
Lifecycle.Event.ON_ANY,
Lifecycle.Event.ON_CREATE,
Lifecycle.Event.ON_START,
Lifecycle.Event.ON_RESUME
)
private val lifecycleJobs = mutableMapOf<Lifecycle, Job>()
val Lifecycle.job: Job
get() = lifecycleJobs[this] ?: createJob().also {
if (it.isActive) {
lifecycleJobs[this] = it
it.invokeOnCompletion { _ -> lifecycleJobs -= this }
}
}
private val lifecycleCoroutineScopes = mutableMapOf<Lifecycle, CoroutineScope>()
val Lifecycle.coroutineScope: CoroutineScope
get() = lifecycleCoroutineScopes[this] ?: job.let { job ->
val newScope = CoroutineScope(job + Dispatchers.Main)
if (job.isActive) {
lifecycleCoroutineScopes[this] = newScope
job.invokeOnCompletion { _ -> lifecycleCoroutineScopes -= this }
}
newScope
}
inline val LifecycleOwner.coroutineScope get() = lifecycle.coroutineScope
fun Lifecycle.createScope(cancelEvent: Lifecycle.Event): CoroutineScope {
return CoroutineScope(createJob(cancelEvent) + Dispatchers.Main)
}
import android.arch.lifecycle.GenericLifecycleObserver
import android.arch.lifecycle.Lifecycle
import android.arch.lifecycle.LifecycleOwner
import kotlinx.coroutines.experimental.suspendCancellableCoroutine
suspend fun Lifecycle.awaitState(state: Lifecycle.State) {
if (currentState.isAtLeast(state)) return // Fast path
suspendCancellableCoroutine<Unit> { c ->
if (currentState == Lifecycle.State.DESTROYED) { // Fast path to cancellation
c.cancel()
return@suspendCancellableCoroutine
}
val observer = object : GenericLifecycleObserver {
override fun onStateChanged(source: LifecycleOwner?, event: Lifecycle.Event) {
if (currentState.isAtLeast(state)) {
removeObserver(this)
c.resume(Unit)
} else if (currentState == Lifecycle.State.DESTROYED) {
c.cancel()
}
}
}
addObserver(observer)
c.invokeOnCancellation { removeObserver(observer) }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment