Created
January 1, 2023 07:44
-
-
Save devrath/ec88c7b99ac38a0ebc0d799be8d9dc96 to your computer and use it in GitHub Desktop.
Publisher Subscriber implementation of state flow in kotlin for android
This file contains hidden or 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
data class EventAction( val eventName: String ) |
This file contains hidden or 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
class MainActivity : AppCompatActivity() { | |
private lateinit var binding: ActivityMainBinding | |
private val viewModel: MainVm by viewModels() | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
binding = ActivityMainBinding.inflate(layoutInflater) | |
setContentView( binding.root) | |
observeUiStates() | |
observerEvents() | |
setOnClickListeners() | |
viewModel.uiLoaded() | |
} | |
/** | |
* Observe events in the subscriber | |
*/ | |
private fun observerEvents() { | |
lifecycleScope.launch { | |
PublisherEventBus.subscribe<EventAction> { event -> | |
Snackbar.make(binding.root, event.eventName, Snackbar.LENGTH_SHORT).show(); | |
} | |
} | |
} | |
/** | |
* Set on-click listeners | |
*/ | |
private fun setOnClickListeners() { | |
binding.apply { | |
eventOneBtnId.setOnClickListener { viewModel.triggerEventOne() } | |
eventTwoBtnId.setOnClickListener { viewModel.triggerEventTwo() } | |
} | |
} | |
/** | |
* Subscribe for UI-States | |
*/ | |
private fun observeUiStates() { | |
// Create a new coroutine from the lifecycleScope | |
// since repeatOnLifecycle is a suspend function | |
lifecycleScope.launch { | |
// Suspend the coroutine until the lifecycle is DESTROYED. | |
// repeatOnLifecycle launches the block in a new coroutine every time the | |
// lifecycle is in the STARTED state (or above) and cancels it when it's STOPPED. | |
repeatOnLifecycle(Lifecycle.State.STARTED) { | |
// Safely collect from locations when the lifecycle is STARTED | |
// and stop collecting when the lifecycle is STOPPED | |
viewModel.uiState.collect { | |
// Update UI elements | |
when (it) { | |
MainScreenStates.InitialUiState -> initialState() | |
MainScreenStates.UiLoadedState -> uiLoadedState() | |
} | |
} | |
} | |
// At this point, the lifecycle is DESTROYED! | |
} | |
} | |
private fun uiLoadedState() {} | |
private fun initialState() {} | |
} |
This file contains hidden or 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
sealed class MainScreenStates { | |
object InitialUiState : MainScreenStates() | |
object UiLoadedState : MainScreenStates() | |
} |
This file contains hidden or 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
class MainVm : ViewModel() { | |
private val _uiState = MutableStateFlow<MainScreenStates>(MainScreenStates.InitialUiState) | |
val uiState: StateFlow<MainScreenStates> = _uiState.asStateFlow() | |
fun uiLoaded() { | |
_uiState.value = MainScreenStates.UiLoadedState | |
} | |
fun triggerEventOne() { | |
viewModelScope.launch { | |
PublisherEventBus.publish(EventAction("Event-1")) | |
} | |
} | |
fun triggerEventTwo() { | |
viewModelScope.launch { | |
PublisherEventBus.publish(EventAction("Event-2")) | |
} | |
} | |
} |
This file contains hidden or 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
object PublisherEventBus { | |
private val _events = MutableSharedFlow<Any>() | |
val events = _events.asSharedFlow() | |
suspend fun publish(event: Any) { | |
_events.emit(event) | |
} | |
suspend inline fun <reified T> subscribe(crossinline onEvent: (T) -> Unit) { | |
events.filterIsInstance<T>() | |
.collectLatest { event -> | |
coroutineContext.ensureActive() | |
onEvent(event) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment