Android Jetpack LiveData

导语

Jetpack简介及其它组件文章
还在担心View层的内存泄漏吗?还在担心一些空指针异常吗?LiveData帮你解决这些问题。

主要内容

  • LiveData是什么
  • LiveData的基本使用
  • postValue和setValue有什么区别
  • observe是如何收到通知的
  • LiveData的粘性事件
  • 如何解决LiveData的粘性事件

具体内容

LiveData是什么

  • LiveData是一个数据持有类
  • 能够感知组件的生命周期
  • 持有的数据可以被观察者观察

简单地来说就是当LiveData持有的数据发生改变的时候,观察者在生命周期处于STARTED或RESUMED状态时,LiveData会更新通知给活跃的观察者。

LiveData的基本使用

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //创建一个LiveData
        MutableLiveData mutableLiveData = new MutableLiveData<>();
        //注册观察者
        mutableLiveData.observe(this, new Observer() {
            @Override
            public void onChanged(String s) {
                Log.d("LiveData", s);
            }
        });
        //其它线程执行完任务对LiveData进行通知
        new Thread(new Runnable() {
            @Override
            public void run() {
                //postValue() 可以在任意线程使用
                mutableLiveData.postValue("通知");
                //setValue() 只能在主线程被调用
//                mutableLiveData.setValue("通知");
            }
        }).start();
    }

}

从上面的代码可以看出,LiveData的基本使用很简单,同时我在代码中注释讲setValue()只能在主线程被调用,接下来我们深入源码再看一下。

postValue和setValue有什么区别

我们可以分别点击postValue和setValue方法,进入它们的源码进行观察。

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

/**
 * Sets the value. If there are active observers, the value will be dispatched to them.
 * 

* This method must be called from the main thread. If you need set a value from a background * thread, you can use {@link #postValue(Object)} * * @param value The new value */ @MainThread protected void setValue(T value) { assertMainThread("setValue"); mVersion++; mData = value; dispatchingValue(null); }

我们可以先看setValue(),可以看到setValue()有个注解@MainThread,方法上面也有注释This method must be called from the main thread.,都表明了这个方法只能在主线程被调用。
我们再跟踪一下postValue方法。postValue方法执行了一行比较重要的代码:ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);看样子是交给主线程去执行一个Runnable。我们进入这个Runnable看一下。

private final Runnable mPostValueRunnable = new Runnable() {
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        //noinspection unchecked
        setValue((T) newValue);
    }
};

我们可以看到,Runnable最终又调用了setValue()
看到这里我们就知道了,postValue()setValue()的作用是相同的,区别是postValue()可以在任意线程调用,setValue()只能在主线程调用。
因为postValue()可以在任意线程调用,所以mPendingData使用了volatile关键字,同时通过synchronized对代码块进行加锁,来保证线程安全。
可以通过setValue方法看到,mData才是我们真正的数据持有者。

observe是如何收到通知的

我们来直接看源码,我们先看LiveData.observe()方法。

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    LiveData.LifecycleBoundObserver wrapper = new LiveData.LifecycleBoundObserver(owner, observer);
    LiveData.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);
}

其中LifecycleBoundObserver持有了我们传入的Observer observer,最后放到了mObservers这个对象了,这个对象是一个Map,所以我们可以一对多。
owner.getLifecycle().addObserver(wrapper)这个代码不重点讲了,这个是Lifecycle提供的功能,如果不了解可以看我其它文章或者去网上找一下。总之就是把wrapperLifecycleOwner的生命周期进行了绑定。
我们再来看setValue()方法是如何通知的。

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

void dispatchingValue(@Nullable LiveData.ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            for (Iterator, LiveData.ObserverWrapper>> iterator =
                 mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

private void considerNotify(LiveData.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);
}

这段代码比较长,不要慌,很简单,有些代码不重要直接往下看。
直接看dispatchingValue(null)到底做了啥。首先我们传入了null,所以会走else,我们看到这里使用IteratormObservers进行遍历,之前说到mObservers是一个map,然后取出值执行considerNotify(iterator.next().getValue())方法,在considerNotify()里,最终调用observer.mObserver.onChanged((T) mData),把结果回调给我们业务层。

LiveData的粘性事件

我们来看一段代码,想一下Log会如何输出。

public class MainActivity extends AppCompatActivity {

    MutableLiveData mutableLiveData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mutableLiveData = new MutableLiveData<>();
        mutableLiveData.postValue("----------------》通知1");
    }

    //点击事件   写在xml里了
    public void observe(View view) {
        mutableLiveData.observe(this, new Observer() {
            @Override
            public void onChanged(String s) {
                Log.d("LiveData", s);
            }
        });
        mutableLiveData.observe(this, new Observer() {
            @Override
            public void onChanged(String s) {
                Log.d("LiveData", s);
            }
        });
    }

}

我们有一个点击事件,放到了xml里,我们先postValue(),通过点击按钮再注册observer,会怎样呢?

2021-03-10 16:52:07.251 25476-25476/com.example.jetpack D/LiveData: ----------------》通知1
2021-03-10 16:52:07.251 25476-25476/com.example.jetpack D/LiveData: ----------------》通知1

居然也收到了通知,这是为什么呢?我们来通过源码看一下。
我们在LiveData.observe()的时候,创建了LifecycleBoundObserverLifecycleBoundObserver继承ObserverWrapper,我们直接来看LifecycleBoundObserverObserverWrapper的代码。

class LifecycleBoundObserver extends LiveData.ObserverWrapper implements GenericLifecycleObserver {

    //...
    
    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        activeStateChanged(shouldBeActive());
    }

    //...
    
}
private abstract class ObserverWrapper {
    final Observer mObserver;
    boolean mActive;
    int mLastVersion = START_VERSION;

    ObserverWrapper(Observer observer) {
        mObserver = observer;
    }

    abstract boolean shouldBeActive();

    boolean isAttachedTo(LifecycleOwner owner) {
        return false;
    }

    void detachObserver() {
    }

    void activeStateChanged(boolean newActive) {
        if (newActive == mActive) {
            return;
        }
        // immediately set active state, so we'd never dispatch anything to inactive
        // owner
        mActive = newActive;
        boolean wasInactive = LiveData.this.mActiveCount == 0;
        LiveData.this.mActiveCount += mActive ? 1 : -1;
        if (wasInactive && mActive) {
            onActive();
        }
        if (LiveData.this.mActiveCount == 0 && !mActive) {
            onInactive();
        }
        if (mActive) {
            dispatchingValue(this);
        }
    }
}

LifecycleBoundObserver最终还继承了LifecycleEventObserverLifecycleEventObserver有一个方法onStateChanged(),首先要了解onStateChanged()方法是Lifecycle提供的功能,如果不了解可以看我其它文章或者去网上找一下。总之就是在Lifecycle的生命周期发生改变的时候调用,所以当LiveData.observer()的时候,就会调用到onStateChanged(),然后再调用到activeStateChanged(),最终执行了dispatchingValue(this),这句很熟悉呀,就是和setValue()最终执行的是一样的代码块。不同的是传入的参数不为空了,所以直接执行considerNotify(initiator),不用遍历了。我们再来看一下这个方法我们还没有讲到的地方。

private void considerNotify(LiveData.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);
}

我们一直向下走,直接来到considerNotify方法,重要的一行代码是observer.mLastVersion >= mVersion,分别点击两个version去看一下,就明白了,分别是ObserverWrapper的版本号和LiveData的版本号,ObserverWrapper的版本号大于LiveData的版本号时,我们就返回,反之则执行,也就是说在什么情况下会执行呢?
举例我们刚才的事例代码,当LiveData创建的时候,mVersion的版本号为-1,当LiveData执行setValue的时候,执行mVersion++结果为0,刚创建ObserverWrapper的时候,mLastVersion的版本是-1,这个时候-1 >= 0的结果为false,所以向下执行不会return,把mVersion赋值给ObserverWrappermLastVersion,防止多次被回调,最终执行observer.mObserver.onChanged((T) mData)

如何解决LiveData的粘性事件

网上大多数的方案是通过反射,在第一次observer的时候,修改ObserverWrappermLastVersion的值。
我的解决方案有点不太一样,通过代理模式拦截observer
我也上传到github了,可以给俺点几个小星星,谢谢。

/**
 * Created by guoshichao on 2021/3/10
 * 非粘性LiveData事件
 */
public class NonStickyLiveData extends MutableLiveData {

    static final int START_VERSION = -1;

    private int mVersion = START_VERSION;

    @Override
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
        ObserverProxy observerProxy = new ObserverProxy<>(observer);
        observerProxy.preventNextEvent = mVersion > START_VERSION;
        super.observe(owner, observerProxy);
    }

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

    private class ObserverProxy implements Observer {

        @NonNull
        private final Observer observer;
        private boolean preventNextEvent = false;

        ObserverProxy(@NonNull Observer observer) {
            this.observer = observer;
        }

        @Override
        public void onChanged(@Nullable T t) {
            if (preventNextEvent) {
                preventNextEvent = false;
                return;
            }
            observer.onChanged(t);
        }
    }

}

如果这样写有问题或者会出现bug,欢迎大家联系我。

更多内容戳这里(整理好的各种文集)

你可能感兴趣的:(Android Jetpack LiveData)