banner
jzman

jzman

Coding、思考、自觉。
github

Android Jetpack Component - LiveData

PS: Time management is really important. The better you manage it, the higher your self-discipline will be. Let's encourage each other.

LiveData is an observable data holder class. Unlike regular observables, LiveData is lifecycle-aware. LiveData is also part of the Android Jetpack components. This article will cover the following aspects of learning LiveData:

  1. What is LiveData
  2. Advantages of LiveData
  3. Using LiveData
  4. Custom LiveData
  5. LiveData transformations

What is LiveData#

LiveData is an observable data holder class. Unlike regular observables, LiveData is aware of the lifecycle of Activity, Fragment, and Service. It ensures that LiveData only updates the component observers that are in an active lifecycle state.

If the state of the application component observer is STARTED or RESUMED, LiveData considers the component to be active. The active component will receive data updates from LiveData, while other registered component observers will not receive any data updates.

Advantages of LiveData#

  • Maintains consistency between UI and data: LiveData follows the observer design pattern. When the lifecycle changes, LiveData notifies the corresponding application component (Observer), and when the data changes, it also notifies the UI to update.
  • Avoids memory leaks: The Observer is bound to the Lifecycle object, so when the Lifecycle object is destroyed, these Observers are automatically cleaned up.
  • Avoids crashes when the Activity is inactive: If the observer is in an inactive state, it will not receive any LiveData events.
  • No need to manually handle lifecycles: UI components only observe relevant data and do not stop or resume observation. LiveData automatically manages this based on the specific lifecycle.
  • Always keeps the latest data: If the lifecycle is in a non-active state, it will receive the latest data when transitioning from a non-active state to an active state, such as automatically receiving the latest data when switching from the background to the foreground.
  • Correctly handles configuration changes: If the Activity or Fragment is recreated due to device configuration changes, such as screen rotation, it will immediately receive the latest data.
  • Shared services: With the observation capability of LiveData data, services can be connected or disconnected at any time based on the lifecycle state.

Using LiveData#

Define LiveData data in a specific ViewModel class, and then observe the changes of LiveData data in the corresponding Activity or Fragment. The use of LiveData allows us to store data in the ViewModel instead of the Activity or Fragment, reducing the workload of the Activity and Fragment. The Activity and Fragment are only responsible for managing and displaying the interface, not for storing data, and the data is not affected by configuration changes.

Summary of LiveData usage:

  1. Create a specific LiveData instance in the ViewModel to store data, as shown below:
public class MViewModel extends ViewModel {
    private MutableLiveData<String> data;
    public LiveData<String> getData(){
        if (data == null){
            data = new MutableLiveData<>();
            data.postValue(DataUtil.getData());
        }
        return data;
    }
}
  1. Use the observe or observeForever method of the LiveData object to add the corresponding Activity or Fragment as an observer of the LiveData object, as shown below:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
    MViewModel mViewModel = ViewModelProviders.of(this).get(MViewModel.class);
    mViewModel.getData().observe(this, new Observer<String>() {
        @Override
        public void onChanged(String msg) {
            binding.setData(msg);
        }
    });
}
  1. Use the setValue or postValue method of LiveData to update the data, and then get the updated data in the observer, which is the Activity or Fragment, as shown below:
public void setData(String data) {
    mData.setValue(data);
}

How to create an observer without a LifecycleOwner? You can use the observeForever method of the LiveData object to add a class without a LifecycleOwner as an observer to the observer list, as shown below:

public class NoLifecycleOwner {
    public void print(NViewModel viewModel, final TextView tvData){
        // Use the observeForever method to create an observer without a LifecycleOwner
        viewModel.getData().observeForever(new Observer<String>() {
            @Override
            public void onChanged(String s) {
                tvData.setText("I am an observer without a LifecycleOwner: " + s);
            }
        });
    }
}

However, using observeForever to obtain an observer object will always keep it in an active state, so you need to manually call removeObserver(Observer) to remove the observer.

Custom LiveData#

You can use the lifecycle-aware capability of the LiveData object to provide services externally. It can easily control the start and stop of the service, as shown below:

/**
 * Custom LiveData
 * Powered by jzman.
 * Created on 2018/12/17 0017.
 */
public class CustomLiveData extends LiveData<String> {

    @Override
    protected void onActive() {
        // Called when there are active observers
        // Start the service...
    }

    @Override
    protected void onInactive() {
        // Called when there are no active observers
        // Stop the service...
    }
}

LiveData Transformations#

Lifecycle provides the Transformations utility class to transform the data type of LiveData. It can modify the data type in LiveData before returning it to the observer. For example, converting an int number 1, 2, etc. to Chinese uppercase characters "壹", "贰", etc. How to use it? Create a MapViewModel as follows:

/**
 * LiveData transformations
 * Powered by jzman.
 * Created on 2018/12/17 0017.
 */
public class MapViewModel extends ViewModel {
    private MutableLiveData<Integer> mPrice = new MutableLiveData<>();

    // Map
    private LiveData<String> mMapPrice = Transformations.map(mPrice, new Function<Integer, String>() {
        @Override
        public String apply(Integer input) {
            // Return String
            return Util.getNumberCapital(input);
        }
    });

    // SwitchMap
    private LiveData<String> mSwitchMapPrice = Transformations.switchMap(mPrice, new Function<Integer, LiveData<String>>() {
        @Override
        public LiveData<String> apply(Integer input) {
            // Return LiveData
            MutableLiveData<String> data = new MutableLiveData<>();
            data.postValue(Util.getNumberCapital(input));
            return data;
        }
    });

    public void setPrice(int price) {
        mPrice.setValue(price);
    }

    public LiveData<String> getPrice() {
        // Map
        return mMapPrice;
        // SwitchMap
//        return mSwitchMapPrice;
    }
}

Then, observe the data changes in the Activity:

public class MapActivity extends AppCompatActivity {
    private MapViewModel mapViewModel;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final ActivityMapBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_map);
        mapViewModel = new MapViewModel();
        mapViewModel.getPrice().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                // Convert the number to Chinese uppercase characters
                binding.tvData.setText(s);
            }
        });
    }

    public void btnSetPrice1(View view) {
        mapViewModel.setPrice(1);
    }

    public void btnSetPrice2(View view) {
        mapViewModel.setPrice(2);
    }
}

The Transformations utility class internally uses MediatorLiveData to perform the transformation. You can use MediatorLiveData to implement more data type conversions similar to map and switch.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.