Skip to content

Most visited

Recently visited

navigation

LiveData

LiveData is a data holder class that keeps a value and allows this value to be observed. Unlike a regular observable, LiveData respects the lifecycle of app components, such that the Observer can specify a Lifecycle in which it should observe.

LiveData considers an Observer to be in an active state if the Observer’s Lifecycle is in STARTED or RESUMED state.

public class LocationLiveData extends LiveData<Location> {
    private LocationManager locationManager;

    private SimpleLocationListener listener = new SimpleLocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setValue(location);
        }
    };

    public LocationLiveData(Context context) {
        locationManager = (LocationManager) context.getSystemService(
                Context.LOCATION_SERVICE);
    }

    @Override
    protected void onActive() {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
    }

    @Override
    protected void onInactive() {
        locationManager.removeUpdates(listener);
    }
}

There are three important parts in this implementation of the Location listener:

onActive()
This method is called when the LiveData has an active observer. This means we need to start observing the location updates from the device.
onInactive()
This method is called when the LiveData does not have any active observers. Since no observers are listening, there is no reason to stay connected to the LocationManager service. This is important because staying connected consumes significant battery power without any benefit.
setValue()
Calling this method updates the value of the LiveData instance and notifies active observers about the change.

We can use the new LocationLiveData as follows:

public class MyFragment extends LifecycleFragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LiveData<Location> myLocationListener = ...;
        Util.checkUserStatus(result -> {
            if (result) {
                myLocationListener.observe(this, location -> {
                    // update UI
                });
            }
        });
    }
}

Notice that the observe() method passes the LifecycleOwner as the first argument. Doing so denotes that this observer should be bound to that Lifecycle, meaning:

The fact that LiveData is lifecycle-aware provides us a new opportunity: we can share it between multiple activities, fragments, and so on. To keep our example simple, we can make it singleton as follows:

public class LocationLiveData extends LiveData<Location> {
    private static LocationLiveData sInstance;
    private LocationManager locationManager;

    @MainThread
    public static LocationLiveData get(Context context) {
        if (sInstance == null) {
            sInstance = new LocationLiveData(context.getApplicationContext());
        }
        return sInstance;
    }

    private SimpleLocationListener listener = new SimpleLocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setValue(location);
        }
    };

    private LocationLiveData(Context context) {
        locationManager = (LocationManager) context.getSystemService(
                Context.LOCATION_SERVICE);
    }

    @Override
    protected void onActive() {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
    }

    @Override
    protected void onInactive() {
        locationManager.removeUpdates(listener);
    }
}

Now the fragment can use it as follows:

public class MyFragment extends LifecycleFragment {
    public void onActivityCreated (Bundle savedInstanceState) {
        Util.checkUserStatus(result -> {
            if (result) {
                LocationLiveData.get(getActivity()).observe(this, location -> {
                   // update UI
                });
            }
        });
  }
}

There might be multiple fragments and activities that are observing our MyLocationListener instance, and LiveData gracefully manages them such that it connects to the system service only if any of them is visible (that is, active).

The LiveData class provides the following advantages:

Transformations of LiveData

Sometimes, you may want to make changes to the LiveData value before dispatching it to the observers, or you may need to return a different LiveData instance based on the value of another one.

The Lifecycle package provides a Transformations class that includes helper methods for these operations.

Transformations.map()

Applies a function on the LiveData value, and propagates the result downstream.

LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
    user.name + " " + user.lastName
});

Transformations.switchMap()

Similar to map(), applies a function to the value and unwraps and dispatches the result downstream. The function passed into switchMap() must return a Lifecycle.

private LiveData<User> getUser(String id) {
  ...;
}

LiveData<String> userId = ...; LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );

Using these transformations allows carrying over the observer Lifecycle information across the chain such that these transformations aren't calculated unless an observer observes the returned LiveData. This lazy calculation nature of transformations allows implicitly passing down lifecycle-related behavior without adding explicit calls or dependencies.

Whenever you think you need a Lifecycle object inside a ViewModel, a transformation is probably the solution.

For instance, let’s assume that we have a UI where the user puts in an address and they receive the postal code for that address. The naive ViewModel for this UI could be like this:

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    public MyViewModel(PostalCodeRepository repository) {
       this.repository = repository;
    }

    private LiveData<String> getPostalCode(String address) {
       // DON'T DO THIS
       return repository.getPostCode(address);
    }
}

If this is the implementation, the UI would need to unregister from the previous LiveData and re-register to the new instance each time they call getPostalCode(). Moreover, if the UI is re-created, it triggers another call to repository.getPostCode() instead of using the previous call’s result.

Instead of using that approach, you can implement the postal code information as a transformation of the address input:

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    private final MutableLiveData<String> addressInput = new MutableLiveData();
    public final LiveData<String> postalCode =
            Transformations.switchMap(addressInput, (address) -> {
                return repository.getPostCode(address);
             });

  public MyViewModel(PostalCodeRepository repository) {
      this.repository = repository
  }

  private void setInput(String address) {
      addressInput.setValue(address);
  }
}

Notice that we’ve even made the postalCode field public final, because it never changes. It is defined as a transformation of the addressInput such that, when addressInput changes, if there is an active observer, repository.getPostCode() is called. If there are no active observers at the time of the call, no calculations are made until an observer is added.

This mechanism allows lower levels of the application to create LiveData objects that are lazily calculated on demand. ViewModel can easily obtain them and define transformation rules on top of them.

Creating new transformations

There are a dozen different specific transformation that may be useful in your application, but they aren’t provided by default. To implement your own transformation you can you use the MediatorLiveData class, which is specially created to properly listen to other LiveData instances and process events emitted by them. MediatorLiveData takes cares to correctly propagate its active/inactive states to the source LiveData. You can check the implementation of the Transformations class for details.

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.