In this post, I will show you the best practices for Implementing an Event bus with RxJava. The RxBus that I’m going to demonstrate that very helpful for state propagation. So guys, let’s started.
1. Create an Android Project named RxBus Example
//RxJava implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
2. Create a simple RX bus that emits the data to the subscribers using Observable
package com.rxbusexample import io.reactivex.Observable import io.reactivex.subjects.PublishSubject /* * Singleton instance * A simple rx bus that emits the data to the subscribers using Observable */ object RxBus { private val publisher = PublishSubject.create<Any>() fun publish(event: Any) { publisher.onNext(event) } // Listen should return an Observable and not the publisher // Using ofType we filter only events that match that class type fun <T> listen(eventType: Class<T>): Observable<T> = publisher.ofType(eventType) }
3. Create a class named is RxBusEvent
package com.rxbusexample class RxBusEvent { data class ProgressEvent( val showDialog: Boolean, val message: String? = null ) data class LogOut(val logout: Boolean) data class MessageEvent(val message: String) }
4. How to use this RxBus
package com.rxbusexample import android.os.CountDownTimer import android.os.Handler import java.util.* import java.util.concurrent.TimeUnit /** * @timer is timer value in milliseconds (suppose 5 min = 5*60*1000) * @interval is a time interval of one count ideally it should be 1000 */ class CountDownTimer(timer: Long, interval: Long) : CountDownTimer(timer, interval) { companion object { private const val SECONDS = 60 } override fun onTick(millisUntilFinished: Long) { val textToShow = String.format( Locale.getDefault(), "%02d min: %02d sec", TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) % SECONDS, TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) % SECONDS ) // Publish MessageEvents RxBus.publish(RxBusEvent.MessageEvent(textToShow)) } override fun onFinish() { // Publish ProgressEvent for showing progressbar RxBus.publish(RxBusEvent.ProgressEvent(true, "Logging out ...")) Handler().postDelayed({ // Publish ProgressEvent for dismissing progressbar RxBus.publish(RxBusEvent.ProgressEvent(false, "Log out Successfully")) RxBus.publish(RxBusEvent.LogOut(true)) }, 3000) } }
5. Let’s open the main activity layout file and add below
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textViewCounter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginLeft="16dp" android:layout_marginTop="16dp" android:layout_marginEnd="16dp" android:layout_marginRight="16dp" android:layout_marginBottom="16dp" android:textSize="20sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.29" android:text="Start" /> <TextView android:id="@+id/textViewMessage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/progressBar" tools:text="TextView" /> <ProgressBar android:id="@+id/progressBar" style="?android:attr/progressBarStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="60dp" android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textViewCounter" /> <Button android:id="@+id/buttonStart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="32dp" android:background="@color/colorAccent" android:text="Start" android:textColor="@color/colorWhite" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/buttonStop" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" /> <Button android:id="@+id/buttonStop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="32dp" android:background="@color/colorAccent" android:text="Stop" android:textColor="@color/colorWhite" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/buttonStart" /> </androidx.constraintlayout.widget.ConstraintLayout>
6. Finally, open the MainActivity and listen to the Observable with event type filter
package com.rxbusexample import android.annotation.SuppressLint import android.os.Bundle import android.view.View.GONE import android.view.View.VISIBLE import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { companion object { const val INTERVAL: Long = 1000 const val TIMER_TIME: Long = 1 * 60 * 1000 } @SuppressLint("CheckResult") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val counter = CountDownTimer(TIMER_TIME, INTERVAL) // set click event on start button buttonStart.setOnClickListener { counter.start() } // set click event on stop button buttonStop.setOnClickListener { counter.cancel() textViewCounter.text = "Stop" } // Listen for MessageEvents only RxBus.listen(RxBusEvent.MessageEvent::class.java) .subscribe { textViewCounter.text = it.message } // Listen for ProgressEvent only RxBus.listen(RxBusEvent.ProgressEvent::class.java) .subscribe { textViewMessage.text = it.message progressBar.visibility = if (it.showDialog) VISIBLE else GONE } // Listen for LogOut only RxBus.listen(RxBusEvent.LogOut::class.java) .subscribe { Toast.makeText(this, "Logout Done !", Toast.LENGTH_LONG).show() } /* // Listen for String events only RxBus.listen(String::class.java).subscribe({ println("Im a String event $it") }) // Listen for Int events only RxBus.listen(Int::class.java).subscribe({ println("Im an Int event $it") })*/ } }
Conclusion
In this android app tutorial, we learned to implement event bus with rxjava. I hope it’s helpful for you, then help me by sharing this post with all your friends who learning android app development.
Get Solution Code
Communication between Fragment and Acitivity using RxJava
3 Comments
how we can test this RX-Bus
How would you “unsubscribe” from an event with this solution?
onDestory() you can