继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Android 架构组件之 LiveData

GT9456
关注TA
已关注
手记 89
粉丝 11
获赞 16

LiveData 是一种具有生命周期感知能力的、可观察数据的、持有类。本文将从以下几个方面来介绍 LiveData:

  • LiveData 是什么?为什么要使用 LiveData?
  • 分析 LiveData 的组成及实现原理
  • 介绍 LiveData 中的转换方法
  • 总结使用 LiveData 的步骤

1. LiveData 是什么?为什么要使用 LiveData?

LiveData 可以简单的理解为具有感知生命周期能力的容器。生命周期感知能力的实现,得益于 Android Framework 使用了一下 Lifecycles 中的类。关于 Lifecycle 的详细介绍,可以查看此前的一篇文章 Android 架构组件之 Lifecycle

这里我们简单的总结一下,Lifecycle 组件包括三个组成部分:

  • Lifecycle:Lifecycle是一个定义 Android 生命周期及状态的类。
  • LifecycleOwner 接口,用于连接有生命周期的对象,例如 AppCompatActivity 和 Fragment。
  • LifecycleObserver,用于观察 LifecycleOwner 的接口。

而我们要介绍的 LiveData,是一个 LifecycleObserver,它可以直接感知 Activity 或 Fragment 的生命周期。基于此,使得 LiveData 较其它的容器类,有一下两个优势:

  • 如果Activity 不在屏幕上,LiveData 不会触发没有必要的界面刷新;
  • 如果 Activity 已经被销毁,LiveData 将自动清空与 Observer 的连接。这样屏幕外或者已经销毁 Activity 或 Fragment就不会被意外地调用。

1.1 一个示例,看使用 LiveData 的优势

下面来看一个示例。假设有一个 UI 界面和 LiveData 对象,这个对象保存了你想要在屏幕上显示的数据,界面可以声明“观察”LiveData 对象,也就是说,界面希望在 LiveData 有更新时收到通知,随后界面会使用新数据重新进行绘制。简而言之,LiveData 可以使屏幕上显示的内容与数据随时保持同步。 看示例代码:

LiveData 对象通常保存在 ViewModel 类中,关于 ViewModel 的介绍,可以查看Android 架构组件之 ViewModel

class LiveDataTimerViewModel : ViewModel() {
    private val mElapsedTime = MutableLiveData<Long>()
    private var mInitialTime: Long = 0
    private var timer: Timer? = null

    init {
        mInitialTime = SystemClock.elapsedRealtime()
        timer = Timer()

        // Update the elapsed time every second.
        timer?.scheduleAtFixedRate(object : TimerTask() {
            override fun run() {
                val newValue = (SystemClock.elapsedRealtime() - mInitialTime) / 1000

                // setValue() cannot be called from a background thread so post to main thread.
                mElapsedTime.postValue(newValue)
            }
        }, ONE_SECOND, ONE_SECOND)
    }
    fun getElapsedTime(): LiveData<Long> = mElapsedTime

在 ViewModel 中,声明一个 MutableLiveData 类型的成员变量,用来保存屏幕上要显示的数据,通过 Timer 类,每秒钟更新一次 LiveData 中的数据。

接下来,在 Activity 的 onCreate()方法中,我们可以从 ViewModel 中获取 LiveData,并在 LiveData 上调用 observe()方法,方法中的第一个参数为 Context,在这里为当下的 Activity,第二个参数是“Observer 观察者”,属于方法回调,回调之后界面会被更新,如果需要更新 LiveData,可以调用 setValue()方法或 postValue()方法。

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.chrono_activity_3)
        
        mLiveDataTimerViewModel = ViewModelProvider(this).get(LiveDataTimerViewModel::class.java)
        subscribe()
    }

    private fun subscribe() {
        val elapsedTimeObserver = Observer<Long> {
            val newText = resources.getString(
                R.string.seconds, it
            )
            timer_textview.text = newText
            Log.d("ChronoActivity3", "Updating timer");
        }
        mLiveDataTimerViewModel?.getElapsedTime()?.observe(this, elapsedTimeObserver)
    }

完整的示例代码,在文末给出 GitHub 地址。

setValue()方法或 postValue()方法,两者的区别在于,setValue 只可以在主线程上运行,postValue 只可以在后台线程上运行,调用 setValue 和 postValue 时,LiveData 将通知 Observer,并更新界面。

以上是LiveData的基本介绍以及使用它的优势,除此之外。Room 数据框架可以很友好地支持 LiveData,Room 返回的 LiveData 对象,可以在数据库数据变化时自动收到通知,还可以在后台线程中加载数据,这样我们可以在数据库更新的时候,轻松地更新界面。关于 Room 组件的介绍,可以查看我们的系列文章。

2. 分析 LiveData 的组成及实现原理

2.1 通过类图分析 LiveData 的组成

我们用最新的 lifecycle-livedata:2.2.0-alpha02 版本来分析其原理,先看一张类图。

LiveData_CD.jpg_watermarklogo
通过上面的类图,我们可以看到:
  • 在 LiveData 中定义了三个内部类 ObserverWrapper、LifecycleBoundObserver 和 AlwaysActiveObserver。

  • ObserverWrapper 是 Observer 的一个包装类,在该类中会记录组件是否处在激活状态的信息,shouldBeActive() 方法是一个抽象方法,需要子类去实现,activeStateChanged() 方法会根据组件的状态,回调不同的方法,后面会详细介绍。

  • LifecycleBoundObserver 和 AlwaysActiveObserver 是 ObserverWrapper的子类,LiveData 对组件的注册监听,都是通过这两个类完成的,区别是当使用 observe()方法注册时使用的是 LifecycleBoundObserver,使用observeForever()方法注册时使用的是 AlwaysActiveObserver。LifecycleBoundObserver 还实现了 LifecycleEventObserver 接口,这样LifecycleBoundObserver 就可以通过 onStateChanged()回调方法来监测组件生命周期的变化了。

  • LiveData 是一个抽象类,它有两个子类 MutableLiveData 和 MediatorLiveData,在 LiveData 中有个两个用来完成对组件注册监听的方法 observe() 和 observeForever();有注册监听的方法,就有取消注册监听的方法 removeObserver() 和 removeObservers();因为 LiveData 是一个容器,所以提供了两个设置 Value 的方法 postValue() 和 setValue();onActive() 和 onInactive()是两个回调方法。

  • LiveData 中的两个回调方法 onActive()和 onInactive(),当LiveData 监听的处于激活状态的组件中 observer的个数不为 0 时会调用回调函数onActive(),当 LiveData监听的组件没有处于激活状态,或者组件中 observer 的个数为 0 时调用onInactive()回调函数。

2.2 分析 LiveData 是怎样感知组件生命周期的

在上面的类图中,我们了解了跟 LiveData 相关的类,下面我们来看一下 LiveData 是怎样感知组件生命周期的,当数据更新时又是怎样通知组件的。

LiveData_SD.jpg_watermarklogo

先来看 LiveData 是怎样感知组件生命周期的,上面提到了在 LiveData 中有两个用来完成对组件注册监听的方法 observe() 和 observeForever(),先来看 observe()方法:

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

observe 的接收一个 LifecycleOwner对象,组件 Activity 和 Fragment 都是实现了LifecycleOwner接口,所以这里的owner可以理解为组件对象。在方法内部创建了LifecycleBoundObserver 对象 wrapper,通过

owner.getLifecycle().addObserver(wrapper)

完成了对组件生命周期的监听,当组件生命周期发生变化时都会回调 wrapper 对象中的onStateChanged()方法,再来看一下 LifecycleBoundObserver 的实现:

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

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

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

可以看到在 LifecycleBoundObserver 中有一个 shouldBeActive()方法,这个方法会在组件状态是STARTED 和 RESUMED 时返回 true。

在 onStateChanged() 方法中会调用到 activeStateChanged()方法,该方法接收一个 boolean 型参数,当参数值为 true 时会调用dispatchingValue()方法,这个方法最终会调用 Observer 的onChanged()回调方法。这也就解释了使用 observe()方法对组件进行监听,只有组件在激活状态STARTED、RESUMED时(对应生命周期 onStart、onResume、onPause)时,才会收到数据更新的通知。当组件在DESTROYED状态时,在onStateChanged()方法内部会调用removeObserver(),因此我们在使用 observe()方法时,可以不考虑 observer 的销毁。

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

我们前面提到使用 observeForever 注册时需要手动取消,来看看是为什么。

@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
        assertMainThread("observeForever");
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        wrapper.activeStateChanged(true);
    }

observeForever() 方法不再接收 LifecycleOwner 对象,在AlwaysActiveObserver 类中的 shouldBeActive()方法的返回值一直是 true,所以使用该方法进行注册监听时,只要数据有变化,不论组件处在什么状态,都会收到通知,这也是为什么要在退出组件时,需要手动调用 removeXXX()方法将注册的 observer 移除。

private class AlwaysActiveObserver extends ObserverWrapper {

        AlwaysActiveObserver(Observer<? super T> observer) {
            super(observer);
        }

        @Override
        boolean shouldBeActive() {
            return true;
        }
    }

2.3 数据更新时 LiveData 又是怎样通知组件的

了解了 LiveData 是怎样感知组件生命周期的,下面再来看一下当数据更新时又是怎样通知组件的。LiveData 提供了两个方法来更新数据,setValue() 方法和 postValue() 方法。区别是 setValue() 方法要在主线程中调用,而 postValue() 方法既可在主线程也可在子线程中调用。先来看一下 setValue() 方法。

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

setValue() 方法中会调用 dispatchingValue() 方法,这个方法最终会调用observe() 或者 observeForever() 传入的Observer对象的 onChanged()回调方法。这就解释了当数据更新时是怎样发送通知的。再来看一下 postValue()方法:

protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
    
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() 方法通过 ArchTaskExecutor 实现了在主线程中执行mPostValueRunnable 对象中的内容,而在mPostValueRunnable中最终会调用setValue() 方法来实现改变 LiveData 存储的数据。

至此,我们知道了 LiveData 是怎样感知组件生命周期的,以及当数据更新时又是怎样通知组件的。

3. LiveData 中的转换方法

LiveData 还提供各种转换方法,包括: map() 、switchMap() 和 MediatorLiveData。

3.1 map

map()方法,可转换 LiveData 的输出,map 可以将 LiveData A 的方法传递到 LiveData B。

livedata_map.png_watermarklogo

比如,上面的示例中将 LiveData 中的 Long 类型,通过 map 方法转换为 String 类型。

var userNameLiveData = Transformations.map(mElapsedTime, { time ->
        "$time 秒"
    }

3.2 switchMap

switchMap() 更改被 LvieData 观察的对象,switchMap与 map 很相似,区别在于,switchMap 给出的是 LiveData,而 Map 给出的是具体值。

livedata_switchmap.png_watermarklogo

举个例子,假设在 Room 数据库中存有很多用户,我们有一个查找数据库用户的方法,我们可以通过 switchMap 将用户 ID与 LiveData 相连,当界面需要查找的 ID 发生变化时,会重新调用查找用户的方法,调用之后生成 LiveData。现在将引用到新找到的用户的 LiveData,这样不管需要查找多少个用户的 LiveData,界面都只需要观察生成的 LiveData 一次。这就是 switchMap 的强大之处。

3.3 MediatorLiveData

MediatorLiveData:用于自定义数据转换,它可以添加或者移除原来的 LiveData 对象,然后多个原 LiveData 对象可以进行组合,作为单一 LiveData 向下传递。

livedata_mediatorlivedata.png_watermarkl

4. 总结使用 LiveData 的步骤

我们先来总结一下使用 LiveData 的步骤:

  • 创建 LiveData 实例以存储某种类型的数据,通常在 ViewModel 类中完成。

  • 创建可定义 onChanged() 方法的 Observer 对象,该方法在 LiveData 对象存储的数据更改时会被调用。通常情况下,在界面(如 Activity 或 Fragment)中创建 Observer 对象。

  • 使用 observe() 方法将 Observer 对象附加到 LiveData 对象。这样会使 Observer 对象订阅 LiveData 对象,以使其收到有关更改的通知。通常情况下,您可以在界面(如 Activity 或 Fragment)中附加 Observer 对象。

LiveData使用起来非常简单,它可以被观察,可以感知生命周期,在很多情况下都能够被灵活运用。

更多内容,可以订阅 我的博客


参考链接

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP