【Android】LiveData 用法及源码解析

瘦欲@ 提交于 2020-08-17 05:54:09

本文讲解 LiveData 用法,以及 LiveData 源码解析。

官方文档:https://developer.android.google.cn/topic/libraries/architecture/livedata

一句话介绍 LiveData :LiveData 是一种可观察的数据存储器类。

 

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

 

为什么需要 LiveData:

  • 能够保证数据和 UI 统一(跟 LiveData 采用观察者模式有关,LiveData 是被观察的,当数据有变化时它会通知 UI 界面来更新数据。)
  • 减少内存泄漏(在 LiveData 中,能够感知到组件的生命周期,当组件的生命周期处于未激活状态或已经处于 Destroy 状态的时候,观察者就会被清理掉。)
  • 当 Activity 停止时不会引起崩溃(因为 Stop 时就已经变成非激活状态,在 LiveData 分发数据的过程中此时这个组件是非激活状态,LiveData 就不会给它分发数据,其实在组件处于 Pause 时就已经不给他分发数据了,只有它再次 Resume 的时候会重新灌入数据。)
  • 不需要额外的手动处理来响应生命周期的变化(因为它内部有观察生命周期 Lifecycle 的组件)
  • 组件和数据相关的内容能实时更新(当组件从后台来到前台时,LiveData 能够将最新的数据通知组件,灌入到组件里面,保证了组件和数据相关的内容能够实时的更新。)
  • 针对 Configuration Change 时,不需要额外的处理来保存数据(因为在屏幕发生改变时,ViewModel 不会变,当它重建的时候会取得上一次的 ViewModel ,ViewModel 对应的也是之前的 LiveData 。LiveData 中的数据没有变,自然的它在重建过程中 LiveData 数据会时时的再次通知到已经重建的新组件中。)
  • 资源共享(通过继承 LiveData ,将类定义成单例模式,在该类封装一些监听系统属性变化,然后通知 LiveData 的观察者。)

 

注:本文使用 Kotlin 编写。

 

导入 LiveData 库:implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"

 

一、用法

1. 自定义布局,一个 TextView ,两个 Button

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="@string/app_name" />

    <Button
        android:id="@+id/btn_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/btn_stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Stop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

2. 自定义 ViewModel 类,在 ViewModel 中改变 LiveData 数据的值。

class MainViewModel : ViewModel() {

    val TAG = "MainViewModel"

    val liveData = MutableLiveData<Int>()
    var stop = false

    fun start() {
        liveData.postValue(0)
        object : Thread() {
            override fun run() {
                while (!stop) {
                    sleep(1000)
                    val value = liveData.value
                    liveData.postValue(value?.plus(1))
                    Log.d(TAG, "run: " + liveData.value.toString())
                }
            }
        }.start()
    }

    fun stop() {
        stop = true
    }
}

3. 在 Activity 里观察 LiveData

class MainActivity : AppCompatActivity() {

    lateinit var mainViewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mainViewModel = ViewModelProvider(this).get<MainViewModel>(MainViewModel::class.java)

        mainViewModel.liveData.observe(this, Observer {
            tv_content.text = it.toString()
        })

        btn_start.setOnClickListener {
            mainViewModel.start()
        }

        btn_stop.setOnClickListener {
            mainViewModel.stop()
        }
    }
}

4. 执行程序,点击 Start Button ,每隔1s,数据会发生改变;点击 Stop Button ,线程关闭,数据不再发生改变。

 

二、源码解析

1. MutableLiveData 源码:

public class MutableLiveData<T> extends LiveData<T> {

    public MutableLiveData(T value) {
        super(value);
    }

    public MutableLiveData() {
        super();
    }

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

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

MutableLiveData 是对 LiveData 的拓展。因为 LiveData 是一个 abstract 的 class ,并不能直接使用。

 

2. LiveData 类图:

观察上面的类图,它有两个实现类,一个是 MutableLiveData ,另一个是 MediatorLiveData 。内部包含了一个 LifecycleBoundObsOvserver ,它实现了 Lifecycle 的 Observer ,它里面的 Observer 进行了对组件生命周期的观察。所以 LiveData 才有了观察组件生命周期的能力。

 

LiveData 函数说明:

  • observe()                       观察函数
  • setValue()                      设置值,必须在主线程调用,直接去改变 UI 界面
  • postValue()                    设置值,主线程或子线程都可以使用,不需要手动切换线程
  • getValue()                      取值
  • hasActiveObservers()  是否有激活状态下的组件
  • hasObservers()             是否有观察者
  • observeForever()          不管 Lifecycle 是不是激活状态,永远都去观察
  • removeObserver()        移除观察者
  • onActive()                      激活回调
  • onInactive()                   解除激活回调,也就是非激活状态

 

实现了 LifecycleEventObserver 接口,用来观察组件生命周期。

 

<<interface>> Observer 用来观察 LiveData 内部 value 的一个观察者。

 

大体流程:LiveData post 或 set value 的时候,首先通过 hasObservers 判断是否有观察者,如果没有就不进行分发,如果有就通过 onActive 遍历是否是激活状态,如果是激活状态就会去调用 <<interface>> Observer 的回调方式,通知它去更新 UI 界面。

 

3. LiveData.observe() 源码

public void observe(LifecycleOwner owner, 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);
}

传进来的 owner 是 Activity 或 Fragment ,然后把 observer 观察者也传进来。

首先判断是否是 DESTROYED 状态,如果是就 return 。

然后会 new 一个 LifecycleBoundObserver ,用来处理生命周期。

把 wrapper put 到 mObservers 容器里面,这个容器是用来遍历用的。

owner 获取 getLifecycle ,添加生命周期观察者 addObserver 。

 

4. LiveData.postValue() 源码

protected void postValue(T value) {
    ...
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

 因为它可以在子线程进行分发,所以它要 postToMainThread 到主线程去:

private final Runnable mPostValueRunnable = new Runnable() {
    @Override
    public void run() {
        ...
        setValue((T) newValue);
    }
};

它最终调的还是 setValue() 。所以说 setValue() 是在主线程进行调用。

 

5. LiveData.setValue() 源码

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

在 set 或 post 时,它的 mVersion 会更新一下,内部的 mData 会被赋值新的 value 。

 

6. LiveData.dispatchingValue() 源码

void dispatchingValue(ObserverWrapper initiator) {
    // 判断是否正在进行分发动作,如果正在进行就直接 return 。
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;

    // 执行 do while 循环
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            // 遍历,通过 Map 进行存储
            for (Iterator < Map.Entry < Observer < ?super T > , ObserverWrapper >> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext();) {
                // 这里的 iterator.next() 对应的是 ObserverWrapper 。
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while ( mDispatchInvalidated );
    mDispatchingValue = false;
}

 

7. LiveData.considerNotify() 源码

private void considerNotify(ObserverWrapper observer) {
    
    // 判断是否是激活状态,如果是非激活状态直接 return 。
    if (!observer.mActive) {
        return;
    }

    // 判断是否是激活状态,如果是非激活状态直接 return 。
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }

    // 判断 当前版本 大于等于 LiveData 总的版本号,就不会继续分发。
    if (observer.mLastVersion >= mVersion) {
        return;
    }

    // 把当前的 Version 赋值给 observer 。
    observer.mLastVersion = mVersion;

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

这个函数解释了 Activity 不会被重复回调的原因。

把 mData 传给当前的 observer 。比如我们的 MainActivity 里面的代码:

mainViewModel.liveData.observe(this, Observer {
    ...
})
public interface Observer<T> {
    void onChanged(T t);
}

最终会回调到 Observer {} 里去执行 tv_content.text = it.toString() 。

 

 

如果本文对你有帮助,请点赞支持!!!

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!