If you have a relatively small collection of key-values that you’d like to save, you should use the SharedPreferences APIs. A SharedPreferences object points to a file containing key-value pairs and provides simple methods to read and write them. The basic implementation may look as follows:

val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) //Read value from default shared preferences

val value = sharedPreferences.getInt(PREFERENCE_KEY, 0) //Increase value and write it back

sharedPreferences.edit().putInt(PREFERENCE_KEY,value + 1).apply()

Let’s imagine we have Activity with two Fragments using data from the same preference key. When the first Fragment changes the value we want to see changes immediately in the second Fragment. Shared Preferences APIs provide Preferences Change Listener for this purpose. The interface defines a callback to be invoked when a shared preference is changed, added or removed. Let’s look at the following example.

In the beginning, we create a new listener. We watch only certain key and when the change occurs, listener updates TextView in the UI. Constants and methods handling UI updates are defined in the parent class. The listener is registered in onResume() , when the Fragment comes to the foreground and UI is ready to be used. In onPause() the listener is unregistered because we don’t want to update UI when the Fragment may not be loaded anymore and also to avoid memory leaks. Listener updates UI only when preferences data change. If we want to have data available immediately after app starts, we have to add another update call in onResume() .

This implementation is straightforward and it provides us with everything we need. However, it has a few drawbacks. We handle data, business logic and UI in the Fragment what is again the separation of concerns design principle. In addition, we have to override a Fragment’s methods to handle its lifecycle. Can we do it better?

Let’s implement the same functionality using ViewModel and LiveData.

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.

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. The ViewModel store and manage UI-related data in a lifecycle conscious way.

In the following code snippet, we create two classes. LiveDataViewModel class provides an instance of the LiveSharedPreferences , which extends LiveData and implements preferences listener. The listener is registered when an object is being used, which means when the object get at least one observer and unregistered when the number of active observers changes to zero.

Android Architecture Components provide methods helping to obtain an instance of ViewModel. The new instance of ViewModel is created when Fragment is created for the first time. When the Fragment is re-created because of configuration changes the same instance of ViewModel is retained. In this case we implement our custom ViewModelFactory to instantiate new LiveDataViewModel and initialize its properties.

To access LiveData we use observe() method, where we define Lifecycle Owner and Observer. Lifecycle Owner is the Fragments itself. It means that Observer callback will not be called when the Fragment is not in active state. When data change during Fragment’s inactive state callback will be invoked when Fragment becomes active again.

ViewModel does not provide LifecycleOwner object. When we want to observe LiveData in ViewModel we have to use observeForever() method. This call is similar to observe with a LifecycleOwner, which is always active. This means that the given observer will receive all events and will never be automatically removed. We should manually call to stop observing this LiveData with removeObserver() .

LifeData is a nice implementation of the lifecycle-aware observer pattern. However, sometimes we don’t need the observer to be lifecycle-aware or we want to access data as a stream or do more advanced transformations. Then RxJava comes to help.

RxJava extends the observer pattern to support sequences of data/events and adds operators that allow you to compose sequences together declaratively while abstracting away concerns about things like low-level threading, synchronization, thread-safety and concurrent data structures. In the following code snippet, we can see the same preferences listener implemented by RxJava.

We create new observable from scratch using Observable.create() . There are plenty of more advanced approaches how to create observable in RxJava (for example syncOnSubscribe() , fromCallable() or fromEmitter() ) but for purpose of this demo, it’s good enough. New preferences listener is registered for each observer which subscribes the observable. And it’s unregistered when the observer disposes of the resource. Observable is subscribed in ViewModel where we can eventually do additional modifications and the result is put to LiveData object which is observed in the Fragment.

In the end, all three approaches get you the same result. Every method has pros and cons and it‘s suitable for a slightly different use case. It’s up to you and your project needs for which solution you decide.