PS: The original article was published on wechat public account: Jzman-blog
LiveData is an observable data holder class that is lifecycle aware, unlike Observable. It is also part of the Android Jetpack component. This article will learn about LiveData from the following aspects:
- What is a LiveData
- The advantages of LiveData
- The use of LiveData
- Custom Livedata
- LiveData conversion
What is a LiveData
LiveData is an Observable data holder class. Unlike Observable, LiveData is aware of the lifecycle of activities, fragments, and services, ensuring that LiveData updates only component observers that are in the state of the Activity lifecycle.
If an application component observer is in the STARTED or RESUMED state, LiveData considers the component to be active and the component will receive data updates from LiveData, while other registered component observers will not receive any data updates.
#### Advantages of LiveData
- Keep the UI consistent with the data: LiveData follows the Observer design pattern, notifying application components (observers) of changes in the life cycle and updating the UI when data changes occur.
- Avoid memory leaks: This Observer is bound to a Lifecycle object and will be automatically cleaned up after the Lifecycle object destory.
- Avoid crashes when an Activity is inactive: if an Observer is inactive, the Observer will not receive any LiveData events.
- No manual lifecycle processing: UI components simply observe the relevant data, not stop or resume observation, and LiveData is automatically managed based on changes in the specific lifecycle.
- Always keep the latest data: If the life cycle is inactive, the latest data will be received when the inactive state becomes active. For example, the latest data will be automatically received when the background is switched to the foreground.
- Handle configuration changes correctly: If an Activity or Fragment is recreated due to a device configuration change, such as screen rotation, it will immediately rereceive the latest data.
- Sharing service: The service can be connected or disconnected at any time according to the life cycle state of Livecycle with the help of the observation capability of LiveData data.
The use of LiveData
Define the LiveData in a specific ViewModel class, and then observe the change of the LiveData in the corresponding Activity or Fragment. The use of LiveData allows us to save the data stored in the LiveData object in the ViewModel instead of the Activity or Fragment, reducing the workload of the Activity and Fragment. Activities and fragments are only responsible for interface management and display, not for saving data, and the data is not affected when the configuration changes.
Summary of LiceData usage:
- Create a concrete LiveData instance in the ViewModel to store the data as follows:
public class MViewModel extends ViewModel {
private MutableLiveData<String> data;
public LiveData<String> getData(a){
if (data == null){
data = new MutableLiveData<>();
data.postValue(DataUtil.getData());
}
returndata; }}Copy the code
- Use the observe or observeForever method of the LiveData object to add the corresponding Activity or Fragment to the observer of the LiveData object, as follows:
@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); }}); }Copy the code
- Update the data using setValue or postValue in LiveData, and then retrieve the updated data in the observer (Activity or Fragment), as follows:
public void setData(String data) {
mData.setValue(data);
}
Copy the code
So how do you create an observer without LifecycleOwner? You can use the observeForever method of the LiveData object to add a class without a LifecycleOwner to the list of observers, as follows:
public class NoLifecycleOwner {
public void print(NViewModel viewModel, final TextView tvData){
// Use the observeForever object to create an observer without LifecycleOwner
viewModel.getData().observeForever(new Observer<String>() {
@Override
public void onChanged(String s) {
tvData.setText("I am an observer without LifecycleOwner :"+s); }}); }}Copy the code
However, using observeForever to get the Observer object will always be active, so we need to manually call removeObserver(Observer) to remove the Observer.
Custom Livedata
You can use the Life cycle awareness capability of the LiveData object to provide services externally, and you can easily control the opening and closing of services, as follows:
/** * Customizable LiveData * Powered by jzman. * Created on 2018/12/170017. */
public class CustomLiveData extends LiveData<String> {
@Override
protected void onActive(a) {
// This method is called by an active observer
// Start the service...
}
@Override
protected void onInactive(a) {
// There are no active observers calling this method
// End the service...}}Copy the code
LiveData conversion
Lifecycle provides a tool class that transforms the data types of the LiveData before it is returned to the viewer. MapViewModel = MapViewModel = MapViewModel = MapViewModel = MapViewModel = MapViewModel = MapViewModel = MapViewModel = MapViewModel = MapViewModel
/** * LiveData conversion * Powered by jzman. * Created on 2018/12/170017. */
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 a String
returnUtil.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));
returndata; }});public void setPrice(int price) {
mPrice.setValue(price);
}
public LiveData<String> getPrice(a) {
//Map
return mMapPrice;
//SwitchMap
// return mSwitchMapPrice;}}Copy the code
Then, watch the data change in the Activity as follows:
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 numbers to Chinese uppercasebinding.tvData.setText(s); }}); }public void btnSetPrice1(View view) {
mapViewModel.setPrice(1);
}
public void btnSetPrice2(View view) {
mapViewModel.setPrice(2); }}Copy the code
The only difference between map and switchMap is that Map converts LiveData to specific types, such as String in the code above, whereas switchMap is LiveData. GetNumberCapital (); getNumberCapital ();
The Map and switchMap methods are internally converted by MediatorLiveData. You can use MediatorLiveData to perform more map and switch conversions.