LiveData详解(上)

一.简介

LiveData类是一种可观察数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(Activity/Fragment/Service等)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者

GitHub:https://developer.android.google.cn/topic/libraries/architecture/livedata

二.基本使用

1.Gradle配置

非androidX项目

implementation "android.arch.lifecycle:extensions:1.1.1"


AndroidX项目

implementation 'androidx.appcompat:appcompat:1.2.0'


这一行依赖,已经可以使用Jetpack的好多组件了,比如ViewModel,比如LiveData等等。当然也可以单个引入,具体见官方文档

Lifecycle  |  Android 开发者  |  Android Developers

2.代码

package com.wjn.rxdemo.livedata;

import android.os.Bundle;
import android.util.Log;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelStoreOwner;

import com.wjn.rxdemo.R;

public class LiveDataActivity extends AppCompatActivity  {

    private MutableLiveData<String> mLiveData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_livedata);
        initLiveData();
        //主线程更新LiveData setValue()方法
        findViewById(R.id.activity_livedata_textview).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mLiveData.setValue("主线程更新LiveData");
                Log.d("LiveDataActivity", "通知 LiveData观察者刷新数据 线程----: " + Thread.currentThread().getName());
            }
        });

        //子线程更新LiveData postValue()方法
        findViewById(R.id.activity_livedata_nametextview).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        mLiveData.postValue("子线程更新LiveData");
                        Log.d("LiveDataActivity", "通知 LiveData观察者刷新数据 线程----: " + Thread.currentThread().getName());
                    }
                }).start();
            }
        });
    }

    /**
     * 初始化LiveData
     */

    private void initLiveData() {
        mLiveData = new MutableLiveData<>();
        mLiveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.d("LiveDataActivity", "LiveData观察者 感知变化 s----: " + s);
                Log.d("LiveDataActivity", "LiveData观察者 感知变化 线程----: " + Thread.currentThread().getName());
            }
        });
    }
}

3.结果

模拟主线程更新数据

D/LiveDataActivity: LiveData观察者 感知变化 s----: 主线程更新LiveData


D/LiveDataActivity: LiveData观察者 感知变化 线程----: main


D/LiveDataActivity: 通知 LiveData观察者刷新数据 线程----: main

模拟子线程更新数据

D/LiveDataActivity: 通知 LiveData观察者刷新数据 线程----: Thread-4


D/LiveDataActivity: LiveData观察者 感知变化 s----: 子线程更新LiveData


D/LiveDataActivity: LiveData观察者 感知变化 线程----: main

至此LiveData的最基本的使用就已经完成。下面详细讲解

三.基本讲解

上述讲述了LiveData的最基本的使用。下面对上面的使用做一些讲解。

1. 创建LiveData对象

上述创建LiveData对象使用的是MutableLiveData类。那么为什么不用LiveData类呢。因为LiveData是一个抽象类MutableLiveData类继承了LiveData类,并重写了两个更新LiveData的方法。

setValue()方法(主线程更新LiveData)postValue()方法(子线程更新LiveData)

2.监听LiveData变化 

mLiveData.observe(this, new Observer<String>() {
    @Override
    public void onChanged(String s) {
        Log.d("LiveDataActivity", "LiveData观察者 感知变化 s----: " + s);
        Log.d("LiveDataActivity", "LiveData观察者 感知变化 线程----: " + Thread.currentThread().getName());
    }
});

observe方法传参是两个。

第一个参数:LifecycleOwner拥有类Activity/Fragment 这里相当于被观察者 他们在生命周期发生改变时告知观察者。

第二个参数:Observer对象。时这里相当于观察者,监听被观察者的状态。

3.更新LiveData

上述通过两个按钮模拟了主线程和子线程更新LiveData的方法。

也就是

主线程更新LiveDatasetValue()方法

mLiveData.setValue("主线程更新LiveData");

子线程更新LiveDatapostValue()方法

mLiveData.postValue("子线程更新LiveData");

那么为什么呢?可不可以倒过来呢?

测试一下 子线程使用setValue()方法

new Thread(new Runnable() {
    @Oerride
    public void run() {
       mLiveData.setValue("子线程更新LiveData");
       Log.d("LiveDataActivity", "通知 LiveData观察者刷新数据 线程----: " + Thread.currentThread().getName());
    }
}).start();

点击按钮发送 报错

com.wjn.rxdemo E/AndroidRuntime: FATAL EXCEPTION: Thread-4
Process: com.wjn.rxdemo, PID: 30432
java.lang.IllegalStateException: Cannot invoke setValue on a background thread
at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:462)
at androidx.lifecycle.LiveData.setValue(LiveData.java:304)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
at com.wjn.rxdemo.livedata.LiveDataActivity$2$1.run(LiveDataActivity.java:39)
at java.lang.Thread.run(Thread.java:929)

显然子线程中更新LiveData只能使用postValue()方法

测试一下 主线程使用postValue()方法

mLiveData.postValue("主线程更新LiveData");

点击按钮发送 正常更新

D/LiveDataActivity: 通知 LiveData观察者刷新数据 线程----: main


D/LiveDataActivity: LiveData观察者 感知变化 s----: 主线程更新LiveData


D/LiveDataActivity: LiveData观察者 感知变化 线程----: main

显然主线程中更新LiveData可以使用postValue()方法

但是 LiveData的更新最好遵循一个原则 原因下面会讲

<1> 主线程中更新LiveData使用setValue()方法

<2> 子线程中更新LiveData使用postValue()方法

4.综上:LiveData的基本使用分三个步骤

<1> 创建LiveData对象 使用MutableLiveData类

<2> 监听LiveData对象 使用observe方法

<3> 更新LiveData对象 使用setValue()postValue()方法

四.源码分析

1.创建LiveData对象

MutableLiveData<String> mLiveData = new MutableLiveData<>();

MutableLiveData源码

/**
 * {@link LiveData} which publicly exposes {@link #setValue(T)} and {@link #postValue(T)} method.
 *
 * @param <T> The type of data hold by this instance
 */
@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

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

继承LiveData抽象类 重写了两个方法postValue()方法setValue()方法

2.LiveData对象发送消息

由上可知,发送消息有两个方法。postValue()方法setValue()方法

postValue()方法源码

/**
 * Posts a task to a main thread to set the given value. So if you have a following code
 * executed in the main thread:
 * <pre class="prettyprint">
 * liveData.postValue("a");
 * liveData.setValue("b");
 * </pre>
 * The value "b" would be set at first and later the main thread would override it with
 * the value "a".
 * <p>
 * If you called this method multiple times before a main thread executed a posted task, only
 * the last value would be dispatched.
 *
 * @param value The new value
 */
protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

注释

<1> 如果在主线程中 发送两个消息 一个用postValue方法一个用setValue方法。 则先收到b 然后收到a

验证

发送

mLiveData.postValue("a");
mLiveData.setValue("b");

接收

/**
 * 初始化LiveData
 */

private void initLiveData() {
   mLiveData = new MutableLiveData<>();
   mLiveData.observe(this, new Observer<String>() {
       @Override
       public void onChanged(String s) {
           Log.d("LiveDataActivity", "LiveData观察者 感知变化 s----: " + s);
       }
   });
}

结果

D/LiveDataActivity: LiveData观察者 感知变化 s----: b


D/LiveDataActivity: LiveData观察者 感知变化 s----: a

结论

因为postValue方法是加了同步的,还要切换到主线程执行。所以虽然第一个发送却是最后一个收到。

<2> 如果在主线程执行已提交的任务之前多次调用此方法,则只会分派最后一个值。

验证

发送

mLiveData.postValue("a");
mLiveData.postValue("b");
mLiveData.postValue("c");

接收

/**
 * 初始化LiveData
 */

private void initLiveData() {
   mLiveData = new MutableLiveData<>();
   mLiveData.observe(this, new Observer<String>() {
       @Override
       public void onChanged(String s) {
           Log.d("LiveDataActivity", "LiveData观察者 感知变化 s----: " + s);
       }
   });
}

结果

D/LiveDataActivity: LiveData观察者 感知变化 s----: c

结论

主线程(子线程 经过测试也是一样)中,多次调用postValue方法,只会收到最后一条消息。综上 使用postValue方法连续发送多条数据时只会收到最新的一条数据。原因下面

源码

同步方法中代码

postTask = mPendingData == NOT_SET;
mPendingData = value;

初次进入

因为初始化时  NOT_SET 和mPendingData 两个值如下

static final Object NOT_SET = new Object();

volatile Object mPendingData = NOT_SET;

所以 mPendingData == NOT_SET成立 即 postTask=true

然后把 传参的value 赋值给 mPendingData

因为首次进入postTask=true,所以 

if (!postTask) {
    return;
}

跳过,执行下面的代码

ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);

mPostValueRunnable抛到主线程执行

mPostValueRunnable源码

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

同样,在同步方法中将 mPendingData 赋值(postValue方法传入的)给一个重新声明的 Object newValue变量。然后 再次将 NOT_SET赋值给mPendingData  然后调用setValue((T) newValue);方法设置数据 。setValue((T) newValue);方法源码下面讲

到这里首次调用postValue方法的流程就走完了。

再次进入(连续)

同样的流程 因为 mPostValueRunnable源码 中 会再次将 NOT_SET赋值给mPendingData 再次postValue时 postTask属性还是true 还是会执行。

总结

也就是说上述说的连续多次调用postValue方法时,只收到最近一次。但是看源码确实是发送了,至于为什么只收到最后一条。下面讲

setValue()方法源码

/**
 * Sets the value. If there are active observers, the value will be dispatched to them.
 * <p>
 * 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);
}

注释

该方法只能主线程中 发送消息

验证

assertMainThread("setValue");
private static void assertMainThread(String methodName) {
    if (!ArchTaskExecutor.getInstance().isMainThread()) {
        throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
                + " thread");
    }
}

结论

setValue方法,只能在主线程发送消息。因为源码中有检测,不是主线程会抛异常。继续

mVersion++;
mData = value;

版本对应的字段 mVersion+1。然后将setValue方法发送的内容赋值给mData。mVersion字段和mData字段下面会用到。 继续

dispatchingValue(null);

事件分发,这个是最核心的东西。

dispatchingValue方法源码

@SuppressWarnings("WeakerAccess") /* synthetic access */
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 boolean mDispatchingValue;

mDispatchingValue属性是全局变量默认值false。所以

if (mDispatchingValue) {
    mDispatchInvalidated = true;
    return;
}

不会执行 跳过。然后立刻将此字段赋值true

mDispatchingValue = true;

然后 执行 下面的do while循环  多次调用时  如果do while 循环没有执行完 则不会执行。继续

因为 dispatchingValue(null);即 传参null。所以看下面的代码

for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
     considerNotify(iterator.next().getValue());
     if (mDispatchInvalidated) {
         break;
     }
}

considerNotify(iterator.next().getValue());

继续

considerNotify方法源码

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

首先 参数ObserverWrapper 对象 是添加观察方法是传入的 下面讲 这里先说明一下 这个对象就是LifecycleOwner类的生成类 可以理解为Activity/Fragment等生命周期类

可以看出 

if (!observer.mActive) {
   return;
}

如果 Activity/Fragment等生命周期类 状态 本身 就是非活跃的 直接return 结束分发事件。

if (!observer.shouldBeActive()) {
    observer.activeStateChanged(false);
    return;
}

如果 Activity/Fragment等生命周期类 状态 变成 非活跃的 调用observer.activeStateChanged(false);方法  然后直接return 结束分发事件  源码下面讲 继续

if (observer.mLastVersion >= mVersion) {
    return;
}

mLastVersion字段:赋值时机

private abstract class ObserverWrapper {
      
    int mLastVersion = START_VERSION;

}
static final int START_VERSION = -1;

也就是说,此字段默认-1。

mVersion字段:赋值时机

 private int mVersion = START_VERSION;

但是在setValue()方法中++了。也就是调用了setValue方法后这个字段加1。

所以第一次 两个字段不相同 跳过

 observer.mLastVersion = mVersion;

立刻,将mVersion字段赋值给mLastVersion字段字段。

最后

observer.mObserver.onChanged((T) mData);

走到这里,也就调用了onChanged方法。然后添加观察者的onChanged方法就会接收到消息了。

总结

<1> LiveData对象发送消息有两个方法。postValue()方法setValue()方法

<2> postValue方法经过同步方法,然后将mPostValueRunnable抛给主线程最后还是会调用setValue()方法

<3> setValue()方法中控制两个字段mVersion:版本mData:发送的消息mVersion字段可以控制是否最后执行observer.mObserver.onChanged((T) mData);操作。

<4> considerNotify()方法是整个过程最核心的方法。此方法可以看出,如果当前Activity/Fragment是销毁状态,或者Activity/Fragment变成销毁状态,或者上一次的版本号比本次的大或者等于。都不会最终执行onChanged方法。

3.LiveData对象监听消息(添加观察者方法)

mLiveData.observe(this, new Observer<String>() {
    @Override
    public void onChanged(String s) {
        Log.d("LiveDataActivity", "LiveData观察者 感知变化 s----: " + s);
    }
});
 

observe方法源码

/**
     * Adds the given observer to the observers list within the lifespan of the given
     * owner. The events are dispatched on the main thread. If LiveData already has data
     * set, it will be delivered to the observer.
     * <p>
     * The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED}
     * or {@link Lifecycle.State#RESUMED} state (active).
     * <p>
     * If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will
     * automatically be removed.
     * <p>
     * When data changes while the {@code owner} is not active, it will not receive any updates.
     * If it becomes active again, it will receive the last available data automatically.
     * <p>
     * LiveData keeps a strong reference to the observer and the owner as long as the
     * given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to
     * the observer &amp; the owner.
     * <p>
     * If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData
     * ignores the call.
     * <p>
     * If the given owner, observer tuple is already in the list, the call is ignored.
     * If the observer is already in the list with another owner, LiveData throws an
     * {@link IllegalArgumentException}.
     *
     * @param owner    The LifecycleOwner which controls the observer
     * @param observer The observer that will receive the events
     */
    @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);
    }

首先,检查线程。如果当前线程不是主线程抛出异常。继续

if (owner.getLifecycle().getCurrentState() == DESTROYED) {
   // ignore
   return;
}

如果,当前LifecycleOwner对象的Lifecycle状态是DESTROYED即Activity/Fragment处于销毁状态直接return不添加观察者方法。继续

LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

LifecycleOwner对象Observer对象 生成LifecycleBoundObserver对象。继续

LifecycleBoundObserver类源码

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
    @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(LifecycleOwner source, 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);
    }
}

可见,LifecycleBoundObserver类 继承 ObserverWrapper类

上面说到的发送消息方法最终走到了核心方法considerNotify方法

该类源码总结 

<1>  继承ObserverWrapper类 传入的observer对象赋值给全局变量 mObserver 这个全局变量就是最后执行 

observer.mObserver.onChanged((T) mData); 

即发送消息的变量。
 

<2> shouldBeActive方法,监听最近一次状态。然后这个方法在在considerNotify方法

if (!observer.shouldBeActive()) {
    observer.activeStateChanged(false);
    return;
}

最后,如果没有return observe方法会执行到

owner.getLifecycle().addObserver(wrapper);

即 将LifecycleBoundObserver对象添加观察者。

五.总结

结合源码,总结出LiveData的几个优点。

<1> 优点1

优点:不易发生内存泄漏。不需要手动解除观察,开发者不需要在onPause或onDestroy方法中解除对LiveData的观察。

原因:observer会在LifecycleOwner状态变为DESTROYED后自动remove。

源码解析:添加观察者时 observe方法中 生成LifecycleBoundObserver对象时 LifecycleBoundObserver类中有一个onStateChanged方法 判断生命周期组件处于DESTROYED状态时会移除Observer对象。具体看上述源码讲解。

<2> 优点2

优点:不会因Activity/Fragment停止而导致崩溃。

原因:如果LifecycleOwner生命周期处于非活跃状态,则它不会接收任何LiveData事件。

源码解析:添加观察者时 observe方法中 会判断生命周期组件处于DESTROYED状态时  如果是 直接return。不会发生消息,所以这种状态也就收不到消息,接收消息的逻辑也不会执行,所以不会因为Activity/Fragment被销毁而崩溃 具体看上述源码讲解。

<3> 优点3

优点:数据始终保持最新状态。

原因:数据更新时 若LifecycleOwner为非活跃状态,那么会在变为活跃时接收最新数据。

源码解析:添加观察者时 observe方法中 生成LifecycleBoundObserver对象时 LifecycleBoundObserver类中有一个onStateChanged方法 该方法会在最后一行执行activeStateChanged(shouldBeActive());方法。

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

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

最后执行到dispatchingValue方法

void dispatchingValue(@Nullable ObserverWrapper initiator) {


}

而dispatchingValue方法最执行considerNotify方法。considerNotify方法源码上面有的。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值