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!
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 anActivity
from anIntentService
that a file has finished downloading.We'll build a very simple app that triggers an
IntentService
to do some work—from anActivity
. OurIntentService
will then communicate back to theActivity
when the work is completed. Our communication channel will be from theLiveData
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 LiveData
component)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.
1. Create an Android Studio ProjectFire up Android Studio 3 and create a new project with an empty activity called
2. Add the Lifecycle ComponentsMainActivity
.After creating a new project, specify the
LifeCycle
and theLiveData
artifacts in your app module'sbuild.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'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 theLifecycleOwner
Activity SubclassHere our
MainActivity
implements theLifecycleOwner
interface.import android.arch.lifecycle.Lifecycleimport android.arch.lifecycle.LifecycleOwnerimport android.arch.lifecycle.LifecycleRegistryimport android.arch.lifecycle.Observerimport android.content.Intentimport android.os.Bundleimport android.support.v7.app.AppCompatActivityimport android.view.Viewimport android.widget.Buttonimport android.widget.TextViewOur activity simply handles the standard activity lifecycle events. Inside each of the lifecycle events, it calls the
4. Create the Layoutregistry.handleLifecycleEvent()
, passing the corresponding event as a parameter.We just have a
Button
that triggers the service. ATextView
(invisible by default) shows the text"Work completed!"
when the service communicates to ourMainActivity
.<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="https://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center_horizontal|center_vertical"> 5. Initialize the WidgetsWe declared our
doWorkButton
andresultTextView
properties inside theMainActivity
class with thelateinit
modifier. We then initialize them inside theonCreate()
method. Anytime thedoWorkButton
is clicked, we disable it (to prevent clicking the button more than once) and start ourMyIntentService
(we'll get to that shortly).class MainActivity : AppCompatActivity(), LifecycleOwner { 6. Create the Custom Event ClassWe 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 ImplementationWe implemented an IntentService called
MyIntentService
. Remember thatIntentService
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 usingstartForeground()
, 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.IntentServiceimport android.arch.lifecycle.MutableLiveDataimport android.content.Intentimport android.os.SystemClockWe create a nameless companion object whose companion class is
MyIntentService
. This companion object has a property calledBUS
, which is an instance ofMutableLiveData
. Remember that companion objects are singletons, so this means that only a single instance ofBUS
exists. We also passed ourCustomEvent
as a type argument to the genericMutableLiveData
class.Remember that the
MutableLiveData
class is a subclass ofLiveData
—and has a method calledpostValue()
that can be called from a background thread.public class MutableLiveData<T> extends LiveData<T> {@Overridepublic void postValue(T value) {super.postValue(value);Inside
onHandleIntent()
, we have our business logic. Remember that this method is called on a background thread (one of the major differences between anIntentService
and a normalService
). TheIntentService
ends immediately by itself when theonHandleIntent()
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 thehasActiveObservers()
method. If there are any, notify and pass our event message to them by using the methodpostValue()
, 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.
<service android:name="MyIntentService"/> 8. Observer ImplementationWe 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 {Inside the
onCreate()
ofMainActivity
, we got the event busBUS
fromMyIntentService
. Then we registered an observer for the event bus (i.e.LiveData
) using theobserve()
method. Next, we registered and inlined an anonymous observer, using theMainActivity
asLifecycleOwner
. This anonymous observer gets notified when any of the following happens:There is already data available in the LiveData
when it subscribes.The data inside the LiveData
gets modified.When either of these occurs, we get the
event
data (from theLiveData
) on the main application thread as input to the lambda. We then do the following inside the lambda's body:Make the resultTextView
visible.Enable the doWorkButton
.Log our custom event property eventProp
value to Logcat.Remember the following about
LiveData
:When a new observer is attached to our LiveData
after a configuration change,LiveData
will 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 LifecycleOwner
is destroyed, the observer will automatically be unsubscribed.Finally, LiveData
is 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 AppFinally, 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, andLiveData
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+!