美文网首页
LiveData学习笔记-源码阅读

LiveData学习笔记-源码阅读

作者: 紫鹰 | 来源:发表于2022-07-15 13:52 被阅读0次

上一篇讲了LiveData的基本使用和postValue丢失信息的问题,接下来就从源码角度看看LiveData是如何工作的。

简单模式的工作原理

之所以称setValue方法发送消息的模式称之为简单模式,因为他是工作在主线程中,不涉及线程切换,也不涉及信息丢弃逻辑。上代码

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

这里代码比较简单,设置了一下版本号,将value保存为全局变量,重点方法为dispatchingValue方法

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

代码比较简单,就不删了,由于上个方法中传入的参数initiator为null,因此,核心方法就是遍历mObservers,并调用considerNotify方法。至于mObservers里面的数据怎么来的,晚点再看,先顺着调用流程看considerNotify方法

private void considerNotify(ObserverWrapper observer) {  
    if (!observer.mActive) {  
        return;  
    }  
    if (!observer.shouldBeActive()) {  
        observer.activeStateChanged(false);  
        return;  
    }  
    if (observer.mLastVersion >= mVersion) {  
        return;  
    }  
    observer.mLastVersion = mVersion;  
    observer.mObserver.onChanged((T) mData);  
}

最后一行,调用了observer的onChanged方法,整个流程算是完成了。

这里还有两个问题observer怎么来的,还有就是considerNotify方法中会校验observer的状态。一个一个来看。

  • observer的注册过程
@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);  
}

添加观察者的方式比较简单 mObservers.putIfAbsent(observer, wrapper);这里还很友好的做了判重的操作。而且该方法只能在主线程中调用,因此不会因为重复添加观察者而造成发送的消息重复

  • observer的生命周期感知能力

还是上面代码,添加观察者的时候,传递了一个参数为LifecycleOwner,方法最后调用了

owner.getLifecycle().addObserver(wrapper);

看到这里,基本上算是明白了,核心就在于Lifecycle,思路还是很清晰的。看看它是如何实现的,源码中提供了一个LifeCycle的实现类LifecycleRegistry,而我们的Fragment和Activity都会持有LifecycleRegistry这个对象

public Lifecycle getLifecycle() {  
    return mLifecycleRegistry;  
}

每当生命周期发生变化时,fragment或者activity都会通过handleLifecycleEvent方法将消息发送给LifecycleRegistry

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {  
    enforceMainThreadIfNeeded("handleLifecycleEvent");  
    moveToState(event.getTargetState());  
}
private void moveToState(State next) {  
    if (mState == next) {  
        return;  
    }  
    mState = next;  
    if (mHandlingEvent || mAddingObserverCounter != 0) {  
        mNewEventOccurred = true;  
        // we will figure out what to do on upper level.  
        return;  
    }  
    mHandlingEvent = true;  
    sync();  
    mHandlingEvent = false;  
}

生命周期感知能力到这就圆满结束了。

接下来看看稍微复杂一点的模式

postValue方式,其实看完setValue方式,这个方式就简单多了

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

先看消息遗弃策略,这里大部分代码都是丢弃消息的逻辑,简单来讲,就是如果还有旧消息没来得及发送的时候来了新消息,则丢弃旧消息。看起来虽然有点迷惑性,异步执行的时候,mPendingData保留的是最新的value,而这个变量保存的才是带发送的消息。由于消息对象使用的是一个变量存储而非集合,因此,消息过载时,定然会有放弃策略。至于为什么如此设计,我也搞不清楚,有人知道的话,辛苦留言告知一下。

postValue这个方法设计初衷就是在子线程中执行,因此需要通过线程转化的方式将消息退入主线程中。ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);这行代码就是线程切换的关键。

这里的runnable比较简单

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

核心方法就是调用了我们之前看过的setValue方法,而这里的value就是上一步保存的全局变量mPendingData。

而postToMainThread最终调用的为DefaultTaskExecutor中的postToMainThread方法

 public void postToMainThread(Runnable runnable) {  
    if (mMainHandler == null) {  
        synchronized (mLock) {  
            if (mMainHandler == null) {  
                mMainHandler = createAsync(Looper.getMainLooper());  
            }  
        }  
    }  
    //noinspection ConstantConditions  
    mMainHandler.post(runnable);  
 }

通过handler发送一个接口,handler会直接执行Runnable的run方法。也就是说这个方法还是执行在主线程中的。

完美结束,可以看出,LiveData的设计还是比较简单的

相关文章

网友评论

      本文标题:LiveData学习笔记-源码阅读

      本文链接:https://www.haomeiwen.com/subject/uoaqirtx.html