Android Jetpack component (four) LiveData

Android Jetpack component series articles:
Android Jetpack component (1) LifeCycle
Android Jetpack component (2) Navigation
Android Jetpack component (3) ViewModel
Android Jetpack component (4) LiveData
Android Jetpack component (5) Room
Android JetPack component (6) DataBinding
Android Jetpack Components (7) Paging
Android Jetpack Components (8) WorkManager

First language

ViewModel stores and manages interface-related data in a way that focuses on the life cycle. When the data changes, it can notify the page through interfaces. However, when there is a lot of data to be notified, it is very redundant to define a large number of interfaces. For this reason, Jetpack provides LiveData components to solve this problem and simplify the development process.
LiveData is an observable data storage class. It is a data container, packaging the data so that the data becomes the observable, and when the data changes, the observer can be notified.
LiveData has life cycle awareness, which follows the life cycle of other application components (such as Activity, Fragmentor Service). This perception capability ensures that LiveData only updates observers of application components that are in an active lifecycle state.

Advantage

  1. Ensure that the interface conforms to the data state
    LiveData follows the observer pattern. When the data changes, LiveData will notify the observer object, and there is no need to update the interface every time the application data changes.
  2. No memory leaks will occur.
    LiveData will be bound to the LifeCycle object and clean up after its associated life cycle is destroyed.
  3. Will not crash due to Activity stopping.
    If the observer's life cycle is inactive (such as in the return stack Activity), it will not receive any LiveData events.
  4. There is no need to manually process the life cycle. The
    interface component only observes the relevant data, and does not stop or resume the observation. LiveData will automatically manage all these operations because it can perceive related life cycle state changes while observing.
  5. The data is always up to date.
    If the life cycle becomes inactive, it will receive the latest data when it becomes active again. For example, once in the background Activitywill receive the latest data immediately after the return to the front desk.
  6. The appropriate configuration changes
    if for configuration changes (such as device rotation) and re-created Activityor Fragmentit will receive the latest available data immediately.
  7. Shared resources
    Extend and encapsulate LiveData using the singleton pattern so that they can be shared in the application.

rely

    implementation 'androidx.lifecycle:lifecycle-livedata:2.3.0'
    //包含了 viewmodel 和 livedata,lifecycle-extensions 中的 API 已弃用
    //implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

use

LiveData is an abstract class and cannot be used directly MutableLiveData. It is usually a direct subclass of it . Complete an example of a counter through LiveData+ViewModel.

public class HomeViewModel extends ViewModel {
    
    
    //value字段用MutableLiveData包装,通常在ViewModel类中完成
    private MutableLiveData<Integer> value;

    public MutableLiveData<Integer> getCurrentValue() {
    
    
        if (value == null) {
    
    
            value = new MutableLiveData<>();
            value.setValue(0);
        }

        return value;
    }
}

After the LiveData is defined, it is necessary to use it to complete the communication between the ViewModel and the page.

 HomeViewModel homeViewModel = new ViewModelProvider(this).get(HomeViewModel.class);
 MutableLiveData<Integer> currentValue = homeViewModel.getCurrentValue();

 currentValue.observe(this, new Observer<Integer>() {
    
    
            @Override
            public void onChanged(Integer integer) {
    
    
                textView.setText(String.valueOf(integer));
            }
 });
 button.setOnClickListener(view -> {
    
    
            homeViewModel.addValue();
 });

In the page, by LiveData.observe()observing the data packaged by LiveData, we can also modify the data through Livedata postValue()or Livedata setValue(), which is postValue()used in non-UI threads and setValue()in UI threads.
The LiveData object of the updated page is stored in the ViewModel instead of being stored in Activityor Fragmentin.

 public void addValue() {
    
    
        if (value.getValue() != null) {
    
    
            value.setValue(value.getValue() + 1);
        }
 }

Generally, LiveData only sends updates when the data changes, and only to active observers. An exception is when an observer changes from an inactive state to an active state. In addition, if the observer changes from the inactive state to the active state for the second time, it will only receive the update if the value has changed since the last time it became active.

Extend LiveData

One of the advantages of LiveData is to share resources and implement a custom singleton of the LiveData class.

public class LiveDataUtil extends LiveData<Integer> {
    
    

    private static LiveDataUtil sInstance;
    private LiveDataUtil manager;

    private SimplePListener listener = new SimpleListener() {
    
    
        @Override
        public void onPriceChanged(Integer value) {
    
    
            setValue(value);
        }
    };

    @MainThread
    public static LiveDataUtil getInstance(String symbol) {
    
    
        if (sInstance == null) {
    
    
            sInstance = new LiveDataUtil(symbol);
        }
        return sInstance;
    }

    private LiveDataUtil(String symbol) {
    
    
        manager = new LiveDataUtil(symbol);
    }

    @Override
    protected void onActive() {
    
    
        manager.requestUpdates(listener);
    }

    private void requestUpdates(SimpleListener listener) {
    
    
        this.listener = listener;
    }

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

    private void removeUpdates(SimpleListener listener) {
    
    
        this.listener = listener;
    }
}

Use it in Activityor Fragmentto get data.

LiveDataUtil.getInstance("flag").observe(this, new Observer<Integer>() {
    
    
            @Override
            public void onChanged(Integer integer) {
    
    
                Log.e("yhj", "onChanged: "+integer);
            }
});

Convert LiveData

In the counter example, the value type is Integer, and the Textviewtext type is set String. We need to change the type. LiveData provides a Transformationsclass for LiveData conversion, which is similar to the RxJava operator.

//aLiveData监听bLiveData内容的变化,变化时将bLiveData转换为相应的内容并通知aLiveData  
liveData = Transformations.map(homeViewModel.getCurrentValue(), String::valueOf);
 
//aLiveData监听bLiveData内容的变化,变化时从bLiveData获取相应的cLiveData,
//添加到aLiveData的监听列表里,即aLiveData同时监听bLiveData和cLiveData,bLiveData的变化只会switch cLiveData,cLiveData变化才会通知aLiveData
aLiveData=Transformations.switchMap(bLiveData, new Function<Integer, LiveData<String>>() {
    
    
            @Override
            public LiveData<String> apply(Integer input) {
    
    
                return cLiveData;
            }
});

Combine multiple LiveData

Monitor multiple LiveData at the same time, and receive a notification as long as one of the LiveData is updated, which MediatorLiveDatais implemented through a subclass of LiveData .

MediatorLiveData<String> mediatorLiveData = new MediatorLiveData<>();
mediatorLiveData.addSource(liveData1, new Observer<String>() {
    
    
            @Override
            public void onChanged(String s) {
    
    
             mediatorLiveData.setValue(s);
            }
});
mediatorLiveData.addSource(liveData2, new Observer<String>() {
    
    
            @Override
            public void onChanged(String s) {
    
    
                mediatorLiveData.setValue(s);
            }
 });

mediatorLiveData.observe(this, new Observer<String>() {
    
    
            @Override
            public void onChanged(String s) {
    
    
            }
});

LiveData implements event bus

There are many ways to implement the event bus, such as EventBus and RxBus implemented by RxJava . You can refer to the two previous articles. Both of these frameworks require special handling of the life cycle. LiveData has its own life cycle awareness capability, and it can perceive data updates. Therefore, an event bus framework with its own life cycle awareness capability can be realized through LiveData.

public class LiveDataBus {
    
    

    private static class Lazy {
    
    
        static LiveDataBus sLiveDataBus = new LiveDataBus();
    }

    public static LiveDataBus get() {
    
    
        return Lazy.sLiveDataBus;
    }

    private ConcurrentHashMap<String, StickyLiveData> mHashMap = new ConcurrentHashMap<>();

    public StickyLiveData with(String eventName) {
    
    

        StickyLiveData liveData = mHashMap.get(eventName);
        if (liveData == null) {
    
    
            liveData = new StickyLiveData(eventName);
            mHashMap.put(eventName, liveData);
        }
        return liveData;
    }

   
    public class StickyLiveData<T> extends LiveData<T> {
    
    

        private String mEventName;

        private T mStickyData;

        private int mVersion = 0;

        public StickyLiveData(String eventName) {
    
    

            mEventName = eventName;
        }

        @Override
        public void setValue(T value) {
    
    
            mVersion++;
            super.setValue(value);
        }

        @Override
        public void postValue(T value) {
    
    
            mVersion++;
            super.postValue(value);
        }

        public void setStickyData(T stickyData) {
    
    
            this.mStickyData = stickyData;
            setValue(stickyData);
        }

        public void postStickyData(T stickyData) {
    
    
            this.mStickyData = stickyData;
            postValue(stickyData);
        }

        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    
    
            observerSticky(owner, observer, false);
        }

        public void observerSticky(LifecycleOwner owner, Observer<? super T> observer, boolean sticky) {
    
    
            super.observe(owner, new WrapperObserver(this, observer, sticky));
            owner.getLifecycle().addObserver(new LifecycleEventObserver() {
    
    
                @Override
                public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
    
    
                    if (event == Lifecycle.Event.ON_DESTROY) {
    
    
                        mHashMap.remove(mEventName);
                    }
                }
            });
        }


        private class WrapperObserver<T> implements Observer<T> {
    
    
            private StickyLiveData<T> mLiveData;
            private Observer<T> mObserver;
            private boolean mSticky;

            //标记该liveData已经发射几次数据了,用以过滤老数据重复接收
            private int mLastVersion = 0;

            public WrapperObserver(StickyLiveData liveData, Observer<T> observer, boolean sticky) {
    
    


                mLiveData = liveData;
                mObserver = observer;
                mSticky = sticky;

                //比如先使用StickyLiveData发送了一条数据。StickyLiveData#version=1
                //那当我们创建WrapperObserver注册进去的时候,就至少需要把它的version和 StickyLiveData的version保持一致
                //用以过滤老数据,否则 岂不是会收到老的数据?
                mLastVersion = mLiveData.mVersion;
            }

            @Override
            public void onChanged(T t) {
    
    
                //如果当前observer收到数据的次数已经大于等于了StickyLiveData发送数据的个数了则return
                if (mLastVersion >= mLiveData.mVersion) {
    
    
                    //但如果当前observer它是关心 黏性事件的,则给他。
                    if (mSticky && mLiveData.mStickyData != null) {
    
    
                        mObserver.onChanged(mLiveData.mStickyData);
                    }
                    return;
                }

                mLastVersion = mLiveData.mVersion;
                mObserver.onChanged(t);
            }
        }

    }
}

Principle of LiveData

LiveData the observe()method receives two parameters, the first one LifecycleOwner, the second is Observer, the source code Observerand Activityassociated with the life cycle, therefore, able to perceive LiveData page lifecycle, to avoid memory leaks may be caused.

 @MainThread
 public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    
    
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
    
    
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
    
    
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
    
    
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
  }

There is one more LiveData observeForever(), which is observe()not much different. The main difference is that when LiveData changes, you can receive notifications no matter what the status of the page is. Therefore, you must call to removeObserver()stop the observation of LiveData after use , otherwise it will cause memory leaks.

 @MainThread
 public void removeObserver(@NonNull final Observer<? super T> observer) {
    
    
        assertMainThread("removeObserver");
        ObserverWrapper removed = mObservers.remove(observer);
        if (removed == null) {
    
    
            return;
        }
        removed.detachObserver();
        removed.activeStateChanged(false);
 }

Guess you like

Origin blog.csdn.net/yang_study_first/article/details/115232130