Created
May 18, 2020 15:54
-
-
Save ZakTaccardi/aadfc8675ab8928d11cbca920359f854 to your computer and use it in GitHub Desktop.
ViewLifecycleScope extensions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.fragment.app.Fragment | |
import androidx.lifecycle.LifecycleOwner | |
import androidx.lifecycle.lifecycleScope | |
import kotlinx.coroutines.CoroutineScope | |
@Suppress("UNCHECKED_CAST") | |
internal class ViewLifecycleScopeImpl( | |
private val fragment: Fragment | |
) : ViewLifecycleScope { | |
override fun launchWhenCreated(block: suspend LifecycleOwnerCoroutineScope.() -> Unit) { | |
fragment.viewLifecycle { | |
lifecycleScope.launchWhenCreated { | |
block(LifecycleOwnerCoroutineScopeImpl(this@viewLifecycle, this)) | |
} | |
} | |
} | |
override fun launchWhenStarted(block: suspend LifecycleOwnerCoroutineScope.() -> Unit) { | |
fragment.viewLifecycle { | |
lifecycleScope.launchWhenStarted { | |
block(LifecycleOwnerCoroutineScopeImpl(this@viewLifecycle, this)) | |
} | |
} | |
} | |
override fun launchWhenResumed(block: suspend LifecycleOwnerCoroutineScope.() -> Unit) { | |
fragment.viewLifecycle { | |
lifecycleScope.launchWhenResumed { | |
block(LifecycleOwnerCoroutineScopeImpl(this@viewLifecycle, this)) | |
} | |
} | |
} | |
} | |
internal class LifecycleOwnerCoroutineScopeImpl( | |
lifecycleOwner: LifecycleOwner, | |
coroutineScope: CoroutineScope | |
) : LifecycleOwnerCoroutineScope, LifecycleOwner by lifecycleOwner, CoroutineScope by coroutineScope |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.fragment.app.Fragment | |
import androidx.lifecycle.LifecycleCoroutineScope | |
import androidx.lifecycle.LifecycleOwner | |
import androidx.lifecycle.Observer | |
import androidx.lifecycle.lifecycleScope | |
import kotlinx.coroutines.CoroutineScope | |
import kotlinx.coroutines.Job | |
import kotlinx.coroutines.flow.Flow | |
import kotlinx.coroutines.flow.collect | |
/** | |
* Emits the new [LifecycleOwner] to [block] when there is a new View [LifecycleOwner]. Usage in a Fragment should be: | |
* | |
* ```kotlin | |
* init { | |
* viewLifecycle { // emit new `LifecycleOwner` for the fragments `View` | |
* // ... | |
* } | |
* } | |
* ``` | |
* | |
* `onCreateView(..)` will have been completed by the time [block] emits, so it will be safe to access your inflated | |
* `View`. | |
* | |
* Under the hood, [Fragment.getViewLifecycleOwnerLiveData] is used to invoke [block] for each | |
* emission | |
* | |
* @see [Fragment.getViewLifecycleOwner] for more info around the behavior. Whenever this is set, | |
* [block] will emit. | |
*/ | |
fun Fragment.viewLifecycle(block: LifecycleOwner.() -> Unit) { | |
viewLifecycleOwnerLiveData.observe( | |
this, | |
Observer { it -> block(it) } | |
) | |
} | |
/** | |
* Provides a special object that allows for the following API in a fragment: | |
* | |
* ```kotlin | |
* init { | |
* viewLifecycleScope.launchWhenCreated { | |
* | |
* } | |
* } | |
* ``` | |
* | |
* This reduces nesting compared to the [Fragment.viewLifecycle] above. | |
*/ | |
val Fragment.viewLifecycleScope get(): ViewLifecycleScope = ViewLifecycleScopeImpl(this) | |
/** | |
* @see [LifecycleCoroutineScope.launchWhenCreated] | |
*/ | |
fun LifecycleOwner.launchWhenCreated(block: suspend CoroutineScope.() -> Unit): Job = lifecycleScope | |
.launchWhenCreated(block) | |
/** | |
* @see [LifecycleCoroutineScope.launchWhenStarted] | |
*/ | |
fun LifecycleOwner.launchWhenStarted(block: suspend CoroutineScope.() -> Unit): Job = lifecycleScope | |
.launchWhenStarted(block) | |
/** | |
* @see [LifecycleCoroutineScope.launchWhenResumed] | |
*/ | |
fun LifecycleOwner.launchWhenResumed(block: suspend CoroutineScope.() -> Unit): Job = lifecycleScope | |
.launchWhenResumed(block) | |
/** | |
* @see [LifecycleCoroutineScope.launchWhenCreated] | |
*/ | |
fun <T> Flow<T>.launchWhenCreatedIn(lifecycleOwner: LifecycleOwner): Job = lifecycleOwner.lifecycleScope | |
.launchWhenCreated { | |
[email protected]() | |
} | |
/** | |
* @see [LifecycleCoroutineScope.launchWhenStarted] | |
*/ | |
fun <T> Flow<T>.launchWhenStartedIn(lifecycleOwner: LifecycleOwner): Job = lifecycleOwner.lifecycleScope | |
.launchWhenStarted { | |
[email protected]() | |
} | |
/** | |
* @see [LifecycleCoroutineScope.launchWhenResumed] | |
*/ | |
fun <T> Flow<T>.launchWhenResumedIn(lifecycleOwner: LifecycleOwner): Job = lifecycleOwner.lifecycleScope | |
.launchWhenResumed { | |
[email protected]() | |
} | |
/** | |
* A variant of [LifecycleCoroutineScope] for a [Fragment.getViewLifecycleOwner] | |
* | |
* Unfortunately [LifecycleCoroutineScope] is a class, so cannot implement it. Note, this "scope" does not implement | |
* [CoroutineScope] as a design choice because coroutines may not be immediately available for launching if this is | |
* referred to when [Fragment.getViewLifecycleOwner] is `null`. | |
*/ | |
interface ViewLifecycleScope { | |
/** | |
* See [LifecycleCoroutineScope.launchWhenCreated] | |
*/ | |
fun launchWhenCreated(block: suspend LifecycleOwnerCoroutineScope.() -> Unit) | |
/** | |
* See [LifecycleCoroutineScope.launchWhenStarted] | |
*/ | |
fun launchWhenStarted(block: suspend LifecycleOwnerCoroutineScope.() -> Unit) | |
/** | |
* See [LifecycleCoroutineScope.launchWhenResumed] | |
*/ | |
fun launchWhenResumed(block: suspend LifecycleOwnerCoroutineScope.() -> Unit) | |
} | |
/** | |
* A class that is both a [LifecycleOwner] and [CoroutineScope]. Used by [ViewLifecycleScope]. | |
* | |
* This helps prevent accidental references to [Fragment]'s [LifecycleOwner] when you originally intend to refer to | |
* [Fragment.getViewLifecycleOwner]. | |
* | |
* @link https://issuetracker.google.com/issues/153858931 for more info | |
*/ | |
interface LifecycleOwnerCoroutineScope : LifecycleOwner, CoroutineScope |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment