Android-LiveData原理解析

LiveData

LiveData是一种具有生命周期感知能力的可观察数据持有类。
LiveData可以保证屏幕上的显示内容和数据一直保持同步。

  • LiveData了解UI界面的状态,如果activity不在屏幕上显示,LiveData不会触发没必要的界面更新,如果activity已经被销毁,会自动清空与Observer的连接,意外的调用就不会发生。
  • LiveData是一个LifecycleOwner,他可以直接感知activity或Fragment的生命周期。

1.定义LiveData

在项目中,LiveData一般是存放在ViewModel中,以保证app配置变更时,数据不会丢失。

2.使用流程

使用流程其实很简单,就是自定义实现一个Observer观察者,然后在Activity或者Fragment中获取到ViewModel,通过ViewModel获取到对应的LiveData,然后给LiveData添加观察者监听,用来监听LiveData中的数据变化,在Observer的onChanged中使用监听回调数据。

在使用LiveData的时候需要注意,LiveData有两个设置数据的方法,一个是setValue,一个是postValue,setValue只能是在主线程使用,而postValue只能在子线程中使用。

3.核心原理

(1)LiveData.observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)

LiveData添加观察者监听,可以看到LiveData的observe方法,使用了@MainThread注释,表明该观察者监听添加的方法,只能是在主线程中使用,如果不是在主线程中使用,则会抛出异常。

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    // 判断是否是在主线程中使用
    assertMainThread("observe");
    // 如果Activity或者Fragment的状态已经是onDestroy,那么就不可以添加观察者监听
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    // 将LifecycleOwner和Observer实现对象封装成LifecycleBoundObserver
    // 而LifecycleBoundObserver是ObserverWrapper的子类,
    // 并且实现了LifecycleEventObserver接口
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    // 往LiveData中的mObservers集合添加对应的wrapper对象
    // 这样做的目的,就是为了用来在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);
}
    // LifecycleRegistry.java
    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

        if (previous != null) {
            return;
        }
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            // it is null we should be destroyed. Fallback quickly
            return;
        }

        boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }

        if (!isReentrance) {
            // we do sync only on the top level.
            sync();
        }
        mAddingObserverCounter--;
    }

    static class ObserverWithState {
        State mState;
        LifecycleEventObserver mLifecycleObserver;

        ObserverWithState(LifecycleObserver observer, State initialState) {
            mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
            mState = initialState;
        }

        void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = getStateAfter(event);
            mState = min(mState, newState);
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
    }
    // Lifecycling.java
    @NonNull
    static LifecycleEventObserver lifecycleEventObserver(Object object) {
        boolean isLifecycleEventObserver = object instanceof LifecycleEventObserver;
        boolean isFullLifecycleObserver = object instanceof FullLifecycleObserver;
        if (isLifecycleEventObserver && isFullLifecycleObserver) {
            return new FullLifecycleObserverAdapter((FullLifecycleObserver) object,
                    (LifecycleEventObserver) object);
        }
        if (isFullLifecycleObserver) {
            return new FullLifecycleObserverAdapter((FullLifecycleObserver) object, null);
        }

        if (isLifecycleEventObserver) {
            return (LifecycleEventObserver) object;
        }

        final Class<?> klass = object.getClass();
        int type = getObserverConstructorType(klass);
        if (type == GENERATED_CALLBACK) {
            List<Constructor<? extends GeneratedAdapter>> constructors =
                    sClassToAdapters.get(klass);
            if (constructors.size() == 1) {
                GeneratedAdapter generatedAdapter = createGeneratedAdapter(
                        constructors.get(0), object);
                return new SingleGeneratedAdapterObserver(generatedAdapter);
            }
            GeneratedAdapter[] adapters = new GeneratedAdapter[constructors.size()];
            for (int i = 0; i < constructors.size(); i++) {
                adapters[i] = createGeneratedAdapter(constructors.get(i), object);
            }
            return new CompositeGeneratedAdaptersObserver(adapters);
        }
        return new ReflectiveGenericLifecycleObserver(object);
    }

在LiveData添加观察者的时候,因为LifecycleBoundObserver实际上也是实现了LifecycleEventObserver接口的,所以在Lifecycling.lifecycleEventObserver对观察者对象做封装的时候,也是直接返回传入的观察者对象,不做任何的处理

(2)LiveData.LifecycleBoundObserver类

LifecycleBoundObserver中封装了LifecycleOwner对象和Observer对象,并且实现了LifecycleEventObserver接口,根据Lifecycle的原理,其实我们可以知道,LifecycleRegistry.addObserver方法,添加的就是LifecycleEventObserver实现了对象。
所以在Activity使用LiveData,添加观察者,其实其内部最终还是给Activity的LifecycleRegistry添加观察者,然后根据Activity的生命周期的变化对LiveData进行通知。

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    // 封装LifecycleOwner实现类对象
    @NonNull
    final LifecycleOwner mOwner;

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
        super(observer);
        mOwner = owner;
    }

    @Override
    boolean shouldBeActive() {
        // 这个其实就是判断Activity当前状态是否大于等于STARTED,比如RESUMED
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

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

    @Override
    boolean isAttachedTo(LifecycleOwner owner) {
        return mOwner == owner;
    }

    @Override
    void detachObserver() {
        mOwner.getLifecycle().removeObserver(this);
    }
}

// ObserverWrapper内部封装了观察者对象
private abstract class ObserverWrapper {
    final Observer<? super T> mObserver;
    boolean mActive;
    int mLastVersion = START_VERSION;

    ObserverWrapper(Observer<? super T> 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);
        }
    }
}
(3)setValue和postValue
@MainThread
protected void setValue(T value) {
    // 判断当前线程是否是主线程,如果不是主线程,就抛出异常
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    // 通知观察者
    dispatchingValue(null);
}


protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    // 分发执行任务
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
setValue的通知更新
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(); ) {
                // 通知观察者,参数是ObserverWrapper类型的对象
                // 其实就是LifecycleBoundObserver对象
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}


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;
    // observer是ObserverWrapper对象,其实现类是LifecycleBoundObserver
    // LifecycleBoundObserver内部封装了mObserver观察者
    // 在这里调用观察者的onChanged()传入新的数据,就是通知观察者进行更新
    observer.mObserver.onChanged((T) mData);
}
postValue的通知更新

postValue的通知更新,其实就是调动任务栈分发任务,而被分发执行的任务实现如下:

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

从这里可以看到,其实postValue在分发的任务中,其内部实现的依然是setValue()方法,只不过是从子线程切换到了主线程进行执行。做了一次线程的切换。
在postValue方法中,其内部调用的是ArchTaskExecutor的postToMainThread方法。

// ArchTaskExecutor.java
private ArchTaskExecutor() {
    mDefaultTaskExecutor = new DefaultTaskExecutor();
    mDelegate = mDefaultTaskExecutor;
}

@Override
public void postToMainThread(Runnable runnable) {
    mDelegate.postToMainThread(runnable);
}

在这里可以看到mDelegate其实就是DefaultTaskExecutor对象
所以mDelegate.postToMainThread(runnable)其实就是调用了DefaultTaskExecutor.postToMainThread方法。

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

在这里可以看到,mMainHandler其实就是通过主线程的Looper实例创建的Handler对象,所以这里Handler发送消息执行任务,就是在主线程中执行该任务。

(4)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;
}

    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);
    }

LiveData在分发消息的时候,会调用dispatchingValue方法循环分发,当消息分发完成之后,其实并不会退出do-while循环,还会在调用considerNotify方法的内部调用observer.activeStateChanged(false);继续执行第二次dispatchingValue方法,也就是说递归执行,在第二次执行的时候,mDispatchingValue = true,就会执行将mDispatchInvalidated = true,那么就会完成dispatchingValue方法的第二次执行,被直接return,那么considerNotify()方法的执行也就完成,此时就会执行considerNotify之后的if条件,因为在dispatchingValue第二次执行的时候将mDispatchInvalidated设置为了true,就直接break跳出了循环,结束了消息的分发。
但是这样的情况,一般是在存在观察者处于ON_STOP或者已经是ON_DESTROY状态的时候。
如果观察者都是处于onResume,那么这个时候会因为mDispatchInvalidated=false而退出了循环,结束分发。

4.粘性事件

但是如果是先setValue,然后再设置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);
    }

因为此时设置Observer的时候,当生命周期发生变化的时候,又会调用回调onStateChanged方法,进而调用activeStateChanged方法

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            // 这里传入的应该是true
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }
// 而第一次的时候,mActive默认是false
        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();
            }
            // 变成了true的时候,又会调用一次分发
            if (mActive) {
                dispatchingValue(this);
            }
        }
    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;
    }

    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;
        observer.mObserver.onChanged((T) mData);
    }

因为在添加Observer之前,已经针对该LiveData设置了一个value,此时添加了观察者,那么又因为生命周期发生了变化,那么该观察者在调用dispatchingValue(this);传入的就不是null,则在do-while循环的if判断中,就会执行if条件,进而调用considerNotify()方法给传入的ObserverWrapper实现类分发消息,那么就会把之前设置的消息分发给了该观察者。
这样的情况就是LiveData的粘性事件。即后注册的观察者接收到了之前LiveData设置的value消息。
那么问题又一次来了,什么时候会触发调用LifecycleBoundObserver的onStateChanged方法呢?
通过LiveData的observe方法进行分析,我们可以知道给LiveData添加观察者的时候,其实就是通过给实现了LifecycleOwner接口的Activity的getLifecycle()方法获取到的LifecycleRegistry对象添加观察者,而LifecycleRegistry中的addObserver方法,就会先满足while条件,然后执行了ObserverWithState.dispatchEvent方法,此时就会调用到了LifecycleBoundObserver.onStateChanged方法
这里为什么会满足while条件呢?calculateTargetState会获取当前Activity生命周期状态的前一个和后一个状态,然后取更小的那个状态,在addObserver的时候,calculateTargetState这里如果activity是onStart的状态,那么calculateTargetState取出的就是CREATED状态,如果activity是onResume的状态,那么这里取出的就是STARTED,不管怎么样都会大于INITIALIZED状态,那么就会满足while条件,此时第二个activity是在onCreate生命周期调用observe方法注册Observer

// LifecycleRegistry.java
    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

        if (previous != null) {
            return;
        }
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            // it is null we should be destroyed. Fallback quickly
            return;
        }

        boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }

        if (!isReentrance) {
            // we do sync only on the top level.
            sync();
        }
        mAddingObserverCounter--;
    }

其实这里个人感觉,应该是在addObserver之后,因为第二个Activity(也就是添加addObserver的)发生了生命周期变化,从onCreate变成了onStart,从onStart变成onResume,此时就会调用moveToState,然后就会调用forwardPass(),然后就会分发消息,因为之前已经postValue或者setValue了,那么在这个LiveData里的mData就不会为null,有消息了,就可以优先分发一次。
满足while条件后,就会调用statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));,这里最终就会调用LifecycleBoundObserver的

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

这里shouldBeActive(),在Activity的最后的生命周期是onResume的时候,就会满足true,那么此时activeStateChanged()传入的参数就是true,而初始的时候,mActive为false

        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);
            }
        }

此时mActive就会重新赋值为true,那么就会调用dispatchingValue()方法,此时dispatchingValue()的参数传入this,那么就不会为false。
一般常用的粘性事件解决方案,其实就是hook修改mLastVersion的值,让这个值变成与mVersion的值一致,但是如果是在onResume或者onStart的生命周期去添加注册观察者,那么常见的粘性事件解决方案中,因为会调用super.observe(),那么就会因为在LifecycleRegistry.addObserver方法中,满足while条件,从而又会进行LifecycleBoundObserver的onStateChanged方法的回调,这样又会出现粘性事件。这样的情况的解决方案,其实可以hook修改mVersion的值,在注册观察者之前,改成-1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 1. 背景 上一篇我们分析了Lifecycles组件的源码,本篇我们将继续分析LiveData组件 相关系列文章:...
    Hankkinn阅读 522评论 0 2
  • 前言 这一节我们将学习LiveData组件,学完本节之后,同学们不仅可以掌握LiveData的使用场景,消息分发原...
    rivenlee阅读 648评论 0 1
  • 目前关于LiveData源码解读的文章非常多了,本文就不重复了,这里只对核心流程做解读。关于源码流程,推荐:And...
    唠嗑008阅读 15,937评论 11 21
  • 推荐指数: 6.0 书籍主旨关键词:特权、焦点、注意力、语言联想、情景联想 观点: 1.统计学现在叫数据分析,社会...
    Jenaral阅读 5,700评论 0 5
  • 昨天,在回家的路上,坐在车里悠哉悠哉地看着三毛的《撒哈拉沙漠的故事》,我被里面的内容深深吸引住了,尽管上学时...
    夜阑晓语阅读 3,777评论 2 9