LifecycleCoroutine
LifecycleCoroutine
图解
sequenceDiagram
LifecycleCoroutineScopeImpl->>LifecycleCoroutineScopeImpl: Lifecycle.coroutineScope.get(),register
activate LifecycleCoroutineScopeImpl
Note right of LifecycleCoroutineScopeImpl: lunch启动协程并lifecycle.addObserver
deactivate LifecycleCoroutineScopeImpl
LifecycleCoroutineScopeImpl->>LifecycleCoroutineScopeImpl: onStateChanged回调时State.DESTROYED自动取消协程
LifecycleCoroutineScopeImpl->>LifecycleCoroutineScopeImpl: launchWhenXxx
activate LifecycleCoroutineScopeImpl
LifecycleCoroutineScopeImpl->>LifecycleController: new LifecycleController
LifecycleController->>LifecycleController: lifecycle.addObserver
LifecycleController->>DispatchQueue: dispatch lifecycle to
LifecycleCoroutineScopeImpl->>PausingDispatcher: withContext(PausingDispatcher, block)
deactivate LifecycleCoroutineScopeImpl
PausingDispatcher->>PausingDispatcher: dispatchQueue.runOrEnqueue(block)
activate PausingDispatcher
PausingDispatcher->>DispatchQueue: dispatch block to
deactivate PausingDispatcher
LifecycleCoroutineScopeImpl
val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope
get() = lifecycle.coroutineScope
val Lifecycle.coroutineScope: LifecycleCoroutineScope
get() {
while (true) {
val existing = mInternalScopeRef.get() as LifecycleCoroutineScopeImpl?
if (existing != null) {
return existing
}
val newScope = LifecycleCoroutineScopeImpl(
this,
SupervisorJob() + Dispatchers.Main.immediate
)
if (mInternalScopeRef.compareAndSet(null, newScope)) {
newScope.register()
return newScope
}
}
}
internal class LifecycleCoroutineScopeImpl(
override val lifecycle: Lifecycle,
override val coroutineContext: CoroutineContext
) : LifecycleCoroutineScope(), LifecycleEventObserver {
init {
if (lifecycle.currentState == Lifecycle.State.DESTROYED) {
coroutineContext.cancel()
}
}
fun register() {
launch(Dispatchers.Main.immediate) {
if (lifecycle.currentState >= Lifecycle.State.INITIALIZED) {
lifecycle.addObserver(this@LifecycleCoroutineScopeImpl)
} else {
coroutineContext.cancel()
}
}
}
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (lifecycle.currentState <= Lifecycle.State.DESTROYED) {
lifecycle.removeObserver(this)
coroutineContext.cancel()
}
}
}
LifecycleCoroutineScope
abstract class LifecycleCoroutineScope internal constructor() : CoroutineScope {
internal abstract val lifecycle: Lifecycle
fun launchWhenCreated(block: suspend CoroutineScope.() -> Unit): Job = launch {
lifecycle.whenCreated(block)
}
fun launchWhenStarted(block: suspend CoroutineScope.() -> Unit): Job = launch {
lifecycle.whenStarted(block)
}
fun launchWhenResumed(block: suspend CoroutineScope.() -> Unit): Job = launch {
lifecycle.whenResumed(block)
}
}
suspend fun <T> Lifecycle.whenCreated(block: suspend CoroutineScope.() -> T): T {
return whenStateAtLeast(Lifecycle.State.CREATED, block)
}
suspend fun <T> Lifecycle.whenStateAtLeast(
minState: Lifecycle.State,
block: suspend CoroutineScope.() -> T
) = withContext(Dispatchers.Main.immediate) {
val job = coroutineContext[Job] ?: error("when[State] methods should have a parent job")
val dispatcher = PausingDispatcher()
val controller =
LifecycleController(this@whenStateAtLeast, minState, dispatcher.dispatchQueue, job)
try {
withContext(dispatcher, block)
} finally {
controller.finish()
}
}
PausingDispatcher dispatch block to dispatchQueue
internal class PausingDispatcher : CoroutineDispatcher() {
@JvmField
internal val dispatchQueue = DispatchQueue()
@ExperimentalCoroutinesApi
override fun dispatch(context: CoroutineContext, block: Runnable) {
dispatchQueue.runOrEnqueue(block)
}
}
LifecycleController dispatch lifecycle to dispatchQueue
internal class LifecycleController(
private val lifecycle: Lifecycle,
private val minState: Lifecycle.State,
private val dispatchQueue: DispatchQueue,
parentJob: Job
) {
private val observer = LifecycleEventObserver { source, _ ->
if (source.lifecycle.currentState == Lifecycle.State.DESTROYED) {
handleDestroy(parentJob)
} else if (source.lifecycle.currentState < minState) {
dispatchQueue.pause()
} else {
dispatchQueue.resume()
}
}
init {
if (lifecycle.currentState == Lifecycle.State.DESTROYED) {
handleDestroy(parentJob)
} else {
lifecycle.addObserver(observer)
}
}
@Suppress("NOTHING_TO_INLINE")
private inline fun handleDestroy(parentJob: Job) {
parentJob.cancel()
finish()
}
@MainThread
fun finish() {
lifecycle.removeObserver(observer)
dispatchQueue.finish()
}
}