|
| 1 | +package com.hoc081098.github_search_kmm.android.compose_utils |
| 2 | + |
| 3 | +import androidx.compose.runtime.Composable |
| 4 | +import androidx.compose.runtime.NonRestartableComposable |
| 5 | +import androidx.compose.runtime.RememberObserver |
| 6 | +import androidx.compose.runtime.getValue |
| 7 | +import androidx.compose.runtime.remember |
| 8 | +import androidx.compose.runtime.rememberUpdatedState |
| 9 | +import androidx.compose.ui.platform.LocalLifecycleOwner |
| 10 | +import androidx.lifecycle.Lifecycle |
| 11 | +import androidx.lifecycle.LifecycleOwner |
| 12 | +import androidx.lifecycle.flowWithLifecycle |
| 13 | +import androidx.lifecycle.repeatOnLifecycle |
| 14 | +import kotlinx.coroutines.CoroutineScope |
| 15 | +import kotlinx.coroutines.Dispatchers |
| 16 | +import kotlinx.coroutines.Job |
| 17 | +import kotlinx.coroutines.cancel |
| 18 | +import kotlinx.coroutines.flow.Flow |
| 19 | +import kotlinx.coroutines.launch |
| 20 | + |
| 21 | +@Composable |
| 22 | +fun <T> rememberFlowWithLifecycle( |
| 23 | + flow: Flow<T>, |
| 24 | + lifecycle: Lifecycle = LocalLifecycleOwner.current.lifecycle, |
| 25 | + minActiveState: Lifecycle.State = Lifecycle.State.STARTED |
| 26 | +): Flow<T> = remember(flow, lifecycle, minActiveState) { |
| 27 | + flow.flowWithLifecycle( |
| 28 | + lifecycle = lifecycle, |
| 29 | + minActiveState = minActiveState |
| 30 | + ) |
| 31 | +} |
| 32 | + |
| 33 | +/** |
| 34 | + * Collect the given [Flow] in a Effect that runs in the [Dispatchers.Main.immediate] coroutine, |
| 35 | + * when [LifecycleOwner.lifecycle] is at least at [minActiveState]. |
| 36 | + */ |
| 37 | +@Composable |
| 38 | +fun <T> Flow<T>.CollectWithLifecycleEffect( |
| 39 | + vararg keys: Any?, |
| 40 | + lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current, |
| 41 | + minActiveState: Lifecycle.State = Lifecycle.State.STARTED, |
| 42 | + collector: (T) -> Unit, |
| 43 | +) { |
| 44 | + val flow = this |
| 45 | + val currentCollector by rememberUpdatedState(collector) |
| 46 | + |
| 47 | + LaunchedEffectInImmediateMain(flow, lifecycleOwner, minActiveState, *keys) { |
| 48 | + lifecycleOwner.repeatOnLifecycle(minActiveState) { |
| 49 | + flow.collect { currentCollector(it) } |
| 50 | + } |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +@Composable |
| 55 | +@NonRestartableComposable |
| 56 | +@Suppress("ArrayReturn") |
| 57 | +private fun LaunchedEffectInImmediateMain( |
| 58 | + vararg keys: Any?, |
| 59 | + block: suspend CoroutineScope.() -> Unit, |
| 60 | +) { |
| 61 | + remember(*keys) { LaunchedEffectImpl(block) } |
| 62 | +} |
| 63 | + |
| 64 | +private class LaunchedEffectImpl( |
| 65 | + private val task: suspend CoroutineScope.() -> Unit, |
| 66 | +) : RememberObserver { |
| 67 | + private val scope = CoroutineScope(Dispatchers.Main.immediate) |
| 68 | + private var job: Job? = null |
| 69 | + |
| 70 | + override fun onRemembered() { |
| 71 | + job?.cancel("Old job was still running!") |
| 72 | + job = scope.launch(block = task) |
| 73 | + } |
| 74 | + |
| 75 | + override fun onForgotten() { |
| 76 | + job?.cancel() |
| 77 | + job = null |
| 78 | + } |
| 79 | + |
| 80 | + override fun onAbandoned() { |
| 81 | + job?.cancel() |
| 82 | + job = null |
| 83 | + } |
| 84 | +} |
0 commit comments