Android developers to LiveData event delivery for those pit

1, why should LiveData used as event delivery

Take advantage of the event bus observer mode to create needless to say (of course, there are many shortcomings), as is good EventBus and RxBus use can play a good role in decoupling, make the process more clear architecture, and will not be passed around each species Callback. But they lack the perception of the View layer (Activity, Fragment, etc.) of the life cycle, the need to manually lift the viewer at the end of the life cycle, manually manage the life cycle is very tedious and error prone.

And Google's Library Lifecycle is to solve this problem, which has observer LiveData is a perception of the life cycle, if it can be perceived to create a life-cycle event bus, not Miya!

2, LiveData as those used for event delivery pit

In with the gradual deepening of LiveData use and understand, especially its "life cycle perception" have a deeper understanding, and slowly discover some pit so used, just like to take this opportunity to share explore. And I usually have to LiveData purely as event delivery to use, in particular, a list of actions (such as additions and deletions involving the operation of IO, View layer needs to know which changes to the data, and the operation is successful, etc., can only be delivered in the form of events).

2.1, postValue data loss

In my previous article also mentioned, you can look directly at the source. postValue just the data that comes pre-existent to mPendingData, then the main thread to throw a Runnable, in this Runnable which then calls the setValue to save up the value actually set up, and the callback observers. If this many times before postValue Runnable executed, in fact, just change the value of mPendingData staging, and will not throw another Runnable again. This problem occurs after the value of the value set out in front of the cover, it will lead to the loss of the event.

 

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        // 这里先把数据暂存起来,后来的数据会覆盖前面的
        mPendingData = value;
    }
    // 这里保证只抛一个 mPostValueRunnable,#-.-
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

2.2, setValue no callback observer

LiveData life cycle of awareness is reflected here, it will not be in the callback "inactive" observer (ie before after onStart to onPause), because then update the View does not make sense, but more dangerous, it will wait until the observer after the new value then activate a callback to him.
But if I pass multiple data (assuming that is guaranteed not to be covered with setValue), an observer who is in an inactive state is no knowledge, they will only receive data at the last time of activation. This event delivery, the events on the performance of the loss of any data center can not receive a pass, that it lost the meaning of the event delivery.

 

// LiveData 通知观察者时调的函数
private void considerNotify(ObserverWrapper observer) {
    // 非激活就直接返回了
    if (!observer.mActive) {
        return;
    }
    // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
    //
    // we still first check observer.active to keep it as the entrance for events. So even if
    // the observer moved to an active state, if we've not received that event, we better not
    // notify for a more predictable notification order.
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    // 每次更新数据都会版本加一,这里保证不会回调之前发送过的数据
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData);
}

2.3, LiveData it is not prepared to pass the event

Can also be seen from the above two points, LiveData (or that it observer) before activating the viewer does not care how many times the data center experienced a change, it will only be an observer at the time of activation, passed to his latest value , the middle value will not work.
Of course,  LiveData the design is not to pass the event, which is a reaction to  View the current state of the View layer just according to the current  LiveData to render the value of the data on the line, when inactive  View is not visible, even if the update did not sense.
I also began to feel the most  LiveData used in the observer mode, and can be a number of different  Fragment data communication between, think of the event bus, now that I think was still too young too naive.

Of course, does not mean that  LiveData is not hopeless, there are Google provides us with a powerful  Lifecycle library, we can not lose yourself making a event  LiveData.

3, does not create a lost event LiveData

LiveData Other features do very perfect, but will lose the event, we want to transform it will break one by one for the above problem.

3.1, postValue problems

For questions postValue, since it is the last call setValue, data is lost because only thrown once Runable, then we own every time the main thread to throw a Runable able to solve this problem

 

/**
 * LiveData 相关的工具类,简化 LiveData 操作
 *
 * @author funnywolf
 * @since 2019-04-22
 */
public class LiveDataUtils {
    private static Handler sMainHandler;
    /**
     * 用 setValue 更新 MutableLiveData 的数据,如果在子线程,就切换到主线程
     */
    public static <T> void setValue(MutableLiveData<T> mld, T d) {
        if (mld == null) {
            return;
        }
        if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
            mld.setValue(d);
        } else {
            postSetValue(mld, d);
        }
    }

    /**
     * 向主线程的 handler 抛 SetValueRunnable
     */
    public static <T> void postSetValue(MutableLiveData<T> mld, T d) {
        if (sMainHandler == null) {
            sMainHandler = new Handler(Looper.getMainLooper());
        }
        sMainHandler.post(SetValueRunnable.create(mld, d));
    }

    private static class SetValueRunnable<T> implements Runnable {
        private final MutableLiveData<T> liveData;
        private final T data;

        private SetValueRunnable(@NonNull MutableLiveData<T> liveData, T data) {
            this.liveData = liveData;
            this.data = data;
        }

        @Override
        public void run() {
            liveData.setValue(data);
        }

        public static <T> SetValueRunnable<T> create(@NonNull MutableLiveData<T> liveData, T data) {
            return new SetValueRunnable<>(liveData, data);
        }
    }
}

Question 3.2, the inactive state

In fact, I think the main problem of "responsibility" is not in the LiveData, but in its viewers, "are you telling me you inactive Yeah, how do I send you the data it, I sent you, in case you problems with it, that in the end who is responsible?. "
We used the viewer is actually LifecycleBoundObserver, calling public void observe (@NonNull LifecycleOwner owner, @NonNull Observer <? Super T> observer) will automatically help us a package such observer, and it will show based on the life cycle of LifecycleOwner the "activation" and "inactive" status.

 

// LifecycleBoundObserver
boolean shouldBeActive() {
    return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

LiveData default there is another observer AlwaysActiveObserver, it is our calling public void observeForever (@NonNull Observer <? Super T> observer) generated when, as the name suggests it will always active, LiveData certainly not for us such observer of life cycle management, we need to call when not using manual public void removeObserver (@NonNull final observer <? super T> observer) observer removed, or it may be a memory leak.

 

// AlwaysActiveObserver
boolean shouldBeActive() {
    return true;
}

This AlwaysActiveObserver seems able to solve our problems, he has been active, and that all events will give him a callback, but need to manage our own life cycle. This is not a historical retrogression it? Finally there is the perception of the life cycle, and now have to manually do?

3.3, create a perception of the life cycle of events is not lost observer

Manually manage the life cycle is absolutely not tolerate, AlwaysActiveObserver problem can be solved just you said, that we build a new observer to manage the problem observeForever and removeObserver. Since it wants to build, it would make a nice first event must not be lost, or else no sense; and life cycle management to its own observer, not simply observeForever and removeObserver, inactive state also like taken into account.
If it wants to manage the life cycle, it would have to use LifecycleOwner, Lifecycle, and their own observations LifecycleOwner the Lifecycle.

 

/**
 * Marks a class as a LifecycleObserver. It does not have any methods, instead, relies on
 * {@link OnLifecycleEvent} annotated methods.
 * <p>
 * @see Lifecycle Lifecycle - for samples and usage patterns.
 */
@SuppressWarnings("WeakerAccess")
public interface LifecycleObserver {

}

Lifecycle outside only to this interface does not contain any pullback, we need to mark the appropriate function with a comment Lane said OnLifecycleEvent notes, will get Lifecycle functions marked by reflection, and then generate a corresponding adapter, interested can look under Lifecycling.getCallback function. For example, we can use

 

public class Observer implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private void onStart() {
        doSomethingOnStart();
    }
}

Get the life cycle, we can at the outset  observeForever, at  Lifecycle.Event.ON_DESTROY the time  removeObserver.
Next to be considered active and inactive state, and since spent  observeForever, and that every event will have callback, if this time  Lifecycle is active, it can be sent out directly to the event. But if inactive, the event can not be directly sent out, we can not lose, then we need to save up first event, then  Lifecycle then save it becomes active when the event sent out. Simple flow chart drawn down.

image

 

/**
 * LiveData 用作事件传递时的观察者
 * 保证所有事件不丢失,保存非激活状态的事件,并能够在激活状态回调,且没有内存泄漏
 *
 * @see AsEventBus
 *
 * @author funnywolf
 * @since 2019-05-18
 */
public class LiveEventObserver<T> implements LifecycleObserver, Observer<T> {
    private LiveData<T> mLiveData;
    private LifecycleOwner mOwner;
    private Observer<? super T> mObserver;

    private final List<T> mPendingData = new ArrayList<>();

    public LiveEventObserver(LiveData<T> liveData, LifecycleOwner owner, Observer<? super T> observer) {
        mLiveData = liveData;
        mOwner = owner;
        mObserver = observer;
        mOwner.getLifecycle().addObserver(this);
        mLiveData.observeForever(this);
    }

    /**
     * 在生命周期结束前的任何时候都可能会调用
     */
    @Override
    public void onChanged(@Nullable T t) {
        if (isActive()) {
            // 如果是激活状态,就直接更新
            mObserver.onChanged(t);
        } else {
            // 非激活状态先把数据存起来
            mPendingData.add(t);
        }
    }

    /**
     * @return 是否是激活状态,即 onStart 之后到 onPause 之前
     */
    private boolean isActive() {
        return mOwner.getLifecycle().getCurrentState()
                .isAtLeast(Lifecycle.State.STARTED);
    }

    /**
     * onStart 之后就是激活状态了,如果之前存的有数据,就发送出去
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    private void onEvent(LifecycleOwner owner, Lifecycle.Event event) {
        if (owner != mOwner) {
            return;
        }
        if (event == Lifecycle.Event.ON_START || event == Lifecycle.Event.ON_RESUME) {
            for (int i = 0; i < mPendingData.size(); i++) {
                mObserver.onChanged(mPendingData.get(i));
            }
            mPendingData.clear();
        }
    }

    /**
     * onDestroy 时解除各方的观察和绑定,并清空数据
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    private void onDestroy() {
        mLiveData.removeObserver(this);
        mLiveData = null;

        mOwner.getLifecycle().removeObserver(this);
        mOwner = null;

        mPendingData.clear();

        mObserver = null;
    }

    public static <T> void bind(@NonNull LiveData<T> liveData,
                                @NonNull LifecycleOwner owner,
                                @NonNull Observer<? super T> observer) {
        if (owner.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
            return;
        }
        new LiveEventObserver<>(liveData, owner, observer);
    }
}

3.4 ensure LiveData events update

3.1 is also said to deal with their own postValue, followed by observers to ensure that our own definition, need to override public void observe (@NonNull LifecycleOwner owner, @NonNull Observer <? Super T> observer).

 

/**
 * 用作事件总线的 {@link MutableLiveData}
 *
 * @see AsEventBus
 *
 * @author funnywolf
 * @since 2019-05-18
 */
public class EventMutableLiveData<T> extends MutableLiveData<T> {
    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        LiveEventObserver.bind(this, owner, observer);
    }

    @Override
    public void postValue(T value) {
        LiveDataUtils.setValue(this, value);
    }
}

/**
 * 用作事件总线的 {@link MediatorLiveData}
 *
 * @see AsEventBus
 *
 * @author funnywolf
 * @since 2019-05-18
 */
public class EventMediatorLiveData<T> extends MediatorLiveData<T> {
    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        LiveEventObserver.bind(this, owner, observer);
    }

    @Override
    public void postValue(T value) {
        LiveDataUtils.setValue(this, value);
    }
}

/**
 * 该注解只用于 {@link androidx.lifecycle.LiveData},用于表示 LiveData 是当成事件总线用的,需要注意:
 * - 观察者在非激活状态(onStart 之后,onPause 之前)时不会产生回调,会丢失事件
 * - postValue 可能会被覆盖,只能用 setValue 来更新值
 * - LiveData 的事件都是黏性的,不使用时手动抛出一个 null 事件,以防下次绑定时会发送存在之前的旧数据;
 *
 * @see LiveDataUtils
 * @see LiveEventObserver
 * @see EventMutableLiveData
 * @see EventMediatorLiveData
 *
 * @author funnywolf
 * @since 2019-05-06
 */
@Target(ElementType.FIELD)
public @interface AsEventBus {
}

4, LiveDataUtils other tools Introduction

The tool bag I usually there are some other commonly used gadget, simply share with you here:

  • StateData contains status and data packaging error messages, because LiveData onChanged only a callback, you can not know the data state, engage in this class
  • RxLiveData inherited from MutableLiveData, and realized Disposable Observer interface, primarily for data conversion from the RxJava to LiveData
  • LiveDataBus, a bus-based LiveData event, but not recommended. Event Bus Try not to use this stuff, unless it is not the occasion does not work, written when very fragrant, very troublesome after maintenance

Attention you can see more advanced information technology dry and Android share oh

Published 56 original articles · won praise 1 · views 2907

Guess you like

Origin blog.csdn.net/chuhe1989/article/details/104641636