|
1 | 1 | # DemoCoroutinesChannelResult |
2 | 2 |
|
| 3 | +Use `Kotlinx Coroutines Channel` to send and receive events between Fragments. |
| 4 | + |
3 | 5 | ## Author: [Petrus Nguyễn Thái Học](https://github.com/hoc081098) |
4 | 6 |
|
5 | 7 | [](https://hits.seeyoufarm.com) |
|
8 | 10 | <img src="demo.gif" height="480"/> |
9 | 11 | </p> |
10 | 12 |
|
| 13 | +## Overview |
| 14 | + |
| 15 | +### 1. Create `MainSingleEvent` class. |
| 16 | + |
| 17 | +```kotlin |
| 18 | +sealed interface MainSingleEvent<out T : MainSingleEvent<T>> { |
| 19 | + interface Key<out T : MainSingleEvent<T>> |
| 20 | + |
| 21 | + val key: Key<T> |
| 22 | + |
| 23 | + data class HomeFragmentResult(val text: String) : MainSingleEvent<HomeFragmentResult> { |
| 24 | + override val key = HomeFragmentResult |
| 25 | + |
| 26 | + companion object : Key<HomeFragmentResult> |
| 27 | + } |
| 28 | + |
| 29 | + data class DashboardFragmentResult(val text: String) : MainSingleEvent<DashboardFragmentResult> { |
| 30 | + override val key = DashboardFragmentResult |
| 31 | + |
| 32 | + companion object : Key<DashboardFragmentResult> |
| 33 | + } |
| 34 | + |
| 35 | + data class HomeDetailsResult(val text: String) : MainSingleEvent<HomeDetailsResult> { |
| 36 | + override val key = HomeDetailsResult |
| 37 | + |
| 38 | + companion object : Key<HomeDetailsResult> |
| 39 | + } |
| 40 | + |
| 41 | + companion object { |
| 42 | + val KEYS: Set<Key<SomeMainSingleEvent>> = setOf( |
| 43 | + HomeFragmentResult, |
| 44 | + DashboardFragmentResult, |
| 45 | + HomeDetailsResult, |
| 46 | + ) |
| 47 | + } |
| 48 | +} |
| 49 | +``` |
| 50 | + |
| 51 | +### 2. Create `MainVM` class with buffered channels as event bus. |
| 52 | + |
| 53 | +```kotlin |
| 54 | +class MainVM : ViewModel() { |
| 55 | + private val eventChannels: Map<MainSingleEvent.Key<SomeMainSingleEvent>, Channel<SomeMainSingleEvent>> = |
| 56 | + MainSingleEvent.KEYS.associateBy( |
| 57 | + keySelector = { it }, |
| 58 | + valueTransform = { Channel<MainSingleEvent<SomeMainSingleEvent>>(Channel.UNLIMITED) } |
| 59 | + ) |
| 60 | + |
| 61 | + fun <T : MainSingleEvent<T>> sendEvent(event: T) { |
| 62 | + checkNotNull(eventChannels[event.key]) { "Must register ${event.key} in MainSingleEvent.Companion.KEYS before using!" } |
| 63 | + .trySend(event) |
| 64 | + .getOrThrow() |
| 65 | + .also { Log.d("@@@", "Sent $event") } |
| 66 | + } |
| 67 | + |
| 68 | + @Suppress("UNCHECKED_CAST") |
| 69 | + fun <T : MainSingleEvent<T>, K : MainSingleEvent.Key<T>> receiveEventFlow(key: K): Flow<T> = |
| 70 | + checkNotNull(eventChannels[key]) { "Must register $key in MainSingleEvent.Companion.KEYS before using!" } |
| 71 | + .receiveAsFlow() |
| 72 | + .map { it as T } |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | +### 3. Send and receive events in `Fragment`s. |
| 77 | + |
| 78 | +We will share `MainVM` instance between `Fragment`s using `Activity` as owner. |
| 79 | + |
| 80 | +```kotlin |
| 81 | +private val mainVM by viewModels<MainVM>( |
| 82 | + ownerProducer = { requireActivity() } |
| 83 | +) |
| 84 | + |
| 85 | +// send in HomeFragment |
| 86 | +mainVM.sendEvent(MainSingleEvent.HomeFragmentResult("Hello from HomeFragment")) |
| 87 | + |
| 88 | +// receive in others |
| 89 | +mainVM.receiveEventFlow(MainSingleEvent.HomeFragmentResult) |
| 90 | + .onEach { Log.d("###", "Received $it") } |
| 91 | + .launchIn(lifecycleScope) |
| 92 | +``` |
0 commit comments