

At the last Google I/O, the Android team released a set of powerful Android Architecture Components. They call it:
A collection of libraries that help you design robust, testable, and maintainable apps. Start with classes for managing your UI component lifecycle and handling data persistence.
If you haven’t learnt about them, you are strongly advised to check out our awesome series here on Envato Tuts+ about Android Architecture Components by Tin Megali. Make sure you go dive in!
Android SDKIntroduction to Android Architecture Components
In this tutorial, I’ll show you how to use the LiveData components from the Android Architectural Components to create an event bus. An event bus can be used to effectively communicate between Android components or between layers of your application—for example, communicating to an Activity from an IntentService that a file has finished downloading.
We’ll build a very simple app that triggers an IntentService to do some work—from an Activity. Our IntentService will then communicate back to the Activity when the work is completed. Our communication channel will be from the LiveData library.
Prerequisites
To be able to follow this tutorial, you’ll need:
- Android Studio 3.0 or higher
- Kotlin plugin 1.1.51 or higher
- a basic understanding of the Android Architectural Components (especially the
LiveDatacomponent) - a basic understanding of an event bus
You can also learn all the ins and outs of the Kotlin language in my Kotlin From Scratch series.
-
Kotlin From Scratch: Variables, Basic Types, and Arrays
-
Kotlin From Scratch: Classes and Objects
1. Create an Android Studio Project
Fire up Android Studio 3 and create a new project with an empty activity called MainActivity.

2. Add the Lifecycle Components
After creating a new project, specify the LifeCycle and the LiveData artifacts in your app module’s build.gradle. Note that as of this writing, the new architectural components are now in a stable version. So this means you can start using them in production apps.
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation "android.arch.lifecycle:runtime:1.0.3"
implementation "android.arch.lifecycle:extensions:1.0.0"
}
These artifacts are available at Google’s Maven repository.
allprojects {
repositories {
google()
jcenter()
}
}
By adding the dependencies, we have taught gradle how to find the library. Make sure you remember to sync your project after adding them.
3. Create the LifecycleOwner Activity Subclass
Here our MainActivity implements the LifecycleOwner interface.
import android.arch.lifecycle.Lifecycle
import android.arch.lifecycle.LifecycleOwner
import android.arch.lifecycle.LifecycleRegistry
import android.arch.lifecycle.Observer
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.Button
import android.widget.TextView
class MainActivity : AppCompatActivity(), LifecycleOwner {
private val registry = LifecycleRegistry(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
}
override fun getLifecycle() : Lifecycle = registry
override fun onStart() {
super.onStart()
registry.handleLifecycleEvent(Lifecycle.Event.ON_START)
}
override fun onResume() {
super.onResume()
registry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
}
override fun onPause() {
super.onPause()
registry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
}
override fun onStop() {
super.onStop()
registry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
}
override fun onDestroy() {
super.onDestroy()
registry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
}
}
Our activity simply handles the standard activity lifecycle events. Inside each of the lifecycle events, it calls the registry.handleLifecycleEvent(), passing the corresponding event as a parameter.
4. Create the Layout
We just have a Button that triggers the service. A TextView (invisible by default) shows the text "Work completed!" when the service communicates to our MainActivity.
5. Initialize the Widgets
We declared our doWorkButton and resultTextView properties inside the MainActivity class with the lateinit modifier. We then initialize them inside the onCreate() method. Anytime the doWorkButton is clicked, we disable it (to prevent clicking the button more than once) and start our MyIntentService (we’ll get to that shortly).
class MainActivity : AppCompatActivity(), LifecycleOwner {
private lateinit var doWorkButton: Button
private lateinit var resultTextView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
// ...
doWorkButton = findViewById(R.id.btn_download)
doWorkButton.setOnClickListener {
doWorkButton.isEnabled = false
resultTextView.visibility = View.INVISIBLE
val serviceIntent = Intent(this, MyIntentService::class.java)
startService(serviceIntent)
}
resultTextView = findViewById(R.id.tv_result)
}
// ...
}
6. Create the Custom Event Class
We just create a simple event message class that we want to pass around on the event bus (or LiveData).
data class CustomEvent (val eventProp: String)
You can add more properties to this class if you want.
7. Service Implementation
We implemented an IntentService called MyIntentService. Remember that IntentService lives outside the activity scope and has a background thread, so it is recommended to perform time-consuming tasks such as downloading or fetching remote data via an API inside it.
However, note that in Android 8.0 if you don’t make your IntentService a foreground service by using startForeground(), the Android system will not allow your service to run more than 1 minute—or else it will be stopped immediately. This mechanism is to efficiently manage system resources such as battery life. If your app is targeting Android 8.0, you are advised to use the JobIntentService instead.
import android.app.IntentService
import android.arch.lifecycle.MutableLiveData
import android.content.Intent
import android.os.SystemClock
class MyIntentService: IntentService("MyIntentService") {
companion object {
var BUS = MutableLiveData()
}
override fun onHandleIntent(intent: Intent?) {
// simulate work
SystemClock.sleep(3000)
// assuming work is done
val event = CustomEvent("value")
if (BUS.hasActiveObservers()) {
BUS.postValue(event)
} else {
// show notification
}
}
}
We create a nameless companion object whose companion class is MyIntentService. This companion object has a property called BUS, which is an instance of MutableLiveData. Remember that companion objects are singletons, so this means that only a single instance of BUS exists. We also passed our CustomEvent as a type argument to the generic MutableLiveData class.
Remember that the MutableLiveData class is a subclass of LiveData—and has a method called postValue() that can be called from a background thread.
public class MutableLiveDataextends LiveData { @Override public void postValue(T value) { super.postValue(value); } @Override public void setValue(T value) { super.setValue(value); } }
Inside onHandleIntent(), we have our business logic. Remember that this method is called on a background thread (one of the major differences between an IntentService and a normal Service). The IntentService ends immediately by itself when the onHandleIntent() method finishes its job.
In our own case, we are simulating work being done (this work can be a file download or communicating with a remote API) by sleeping the current thread for 30 seconds. We then checked if our BUS has any active observers using the hasActiveObservers() method. If there are any, notify and pass our event message to them by using the method postValue(), or else we can simply show a notification (this was not coded in the example above for brevity’s sake).
Remember to include the service in your manifest file.
8. Observer Implementation
We need at least one observer for our mechanism to be useful. So inside the MainActivity class, we are going to subscribe an anonymous observer.
class MainActivity : AppCompatActivity(), LifecycleOwner {
// ...
override fun onCreate(savedInstanceState: Bundle?) {
// ...
MyIntentService.BUS.observe(
this,
Observer { event ->
resultTextView.visibility = View.VISIBLE
downloadButton.isEnabled = true
Log.d("MainActivity", event?.eventProp)
})
}
// ...
}
Inside the onCreate() of MainActivity, we got the event bus BUS from MyIntentService. Then we registered an observer for the event bus (i.e. LiveData) using the observe() method. Next, we registered and inlined an anonymous observer, using the MainActivity as LifecycleOwner. This anonymous observer gets notified when any of the following happens:
- There is already data available in the
LiveDatawhen it subscribes. - The data inside the
LiveDatagets modified.
When either of these occurs, we get the event data (from the LiveData) on the main application thread as input to the lambda. We then do the following inside the lambda’s body:
- Make the
resultTextViewvisible. - Enable the
doWorkButton. - Log our custom event property
eventPropvalue to Logcat.
Remember the following about LiveData:
- When a new observer is attached to our
LiveDataafter a configuration change,LiveDatawill send the last data it received to the observer—even without us explicitly telling it to do so. In other words, it does this automatically. - When the
LifecycleOwneris destroyed, the observer will automatically be unsubscribed. - Finally,
LiveDatais an observable that is lifecycle-aware. According to the docs:
LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.
9. Testing the App
Finally, you can run the app! Click the Do Work button and after 30 seconds, you’ll see the result.

You can get the complete source code from our GitHub repo.
Conclusion
In this tutorial, you learned how to easily use the LiveData components from the Android Architectural Components to create an event bus—so as to effectively communicate with components of your app.
I assume you’re aware of other libraries you can use for the same purpose, such as Android LocalBroadcastManager or the popular greenrobot EventBus to implement an event bus in your Android application. You can see that using the LiveData instead is preferable to them—because you avoid writing boilerplate or verbose code, and LiveData provides you with better flexibility.
To learn more about coding for Android, check out some of our other courses and tutorials here on Envato Tuts+!
AndroidCommunication Within an Android App With EventBus
AndroidHow to Get Started With Push Notifications On Android
Google MapsGetting Started With Google Maps for Android: Basics
Android SDKConcurrency in RxJava 2
Powered by WPeMatico












