Skip to content

Instantly share code, notes, and snippets.

@devrath
Created January 1, 2023 07:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devrath/ec88c7b99ac38a0ebc0d799be8d9dc96 to your computer and use it in GitHub Desktop.
Save devrath/ec88c7b99ac38a0ebc0d799be8d9dc96 to your computer and use it in GitHub Desktop.
Publisher Subscriber implementation of state flow in kotlin for android
data class EventAction( val eventName: String )
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() {}
}
sealed class MainScreenStates {
object InitialUiState : MainScreenStates()
object UiLoadedState : MainScreenStates()
}
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"))
}
}
}
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