Last active
September 26, 2024 17:17
-
-
Save gmk57/330a7d214f5d710811c6b5ce27ceedaa to your computer and use it in GitHub Desktop.
Sending events to UI with Channel/Flow + custom collector (see my first comment for reasons behind it)
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
/** | |
* Starts collecting a flow when the lifecycle is started, and **cancels** the collection on stop. | |
* This is different from `lifecycleScope.launchWhenStarted { flow.collect{...} }`, in which case | |
* the coroutine is just suspended on stop. | |
*/ | |
inline fun <reified T> Flow<T>.collectWhileStarted( | |
lifecycleOwner: LifecycleOwner, | |
noinline action: suspend (T) -> Unit | |
) { | |
object : DefaultLifecycleObserver { | |
private var job: Job? = null | |
init { | |
lifecycleOwner.lifecycle.addObserver(this) | |
} | |
override fun onStart(owner: LifecycleOwner) { | |
job = owner.lifecycleScope.launch { | |
collect { action(it) } | |
} | |
} | |
override fun onStop(owner: LifecycleOwner) { | |
job?.cancel() | |
job = null | |
} | |
} | |
} | |
class MyViewModel : ViewModel() { | |
// You can specify exact buffer size and onBufferOverflow strategy here, or go full blast with Channel.UNLIMITED | |
private val eventChannel = Channel<String>(capacity = 10, onBufferOverflow = BufferOverflow.DROP_OLDEST) | |
val eventFlow = eventChannel.receiveAsFlow() | |
fun sendEvent(element: String) = eventChannel.trySend(element) // `trySend` replaces `offer` since Coroutines 1.5 | |
} | |
class MyFragment : Fragment(R.layout.fragment_my) { | |
private val viewModel: MyViewModel by viewModels() | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
// You can collect flow in `onCreate` using `this` as lifecycleOwner | |
// This is a bit more efficient: `LifecycleObserver` is registered only once | |
viewModel.eventFlow.collectWhileStarted(this) { Log.i(TAG, "event: $it") } | |
} | |
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | |
super.onViewCreated(view, savedInstanceState) | |
// Or you can collect flow in `onViewCreated` using `viewLifecycleOwner` | |
// This more closely resembles a typical LiveData observer | |
viewModel.eventFlow.collectWhileStarted(viewLifecycleOwner) { Log.i(TAG, "event: $it") } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In 2024, your expectations are materializing.
https://android-developers.googleblog.com/2024/05/android-support-for-kotlin-multiplatform-to-share-business-logic-across-mobile-web-server-desktop.html