Android架构组件-LiveData

定义

简单地说,LiveData是一个数据持有类。它具有以下特点:

  • 数据可以被观察者订阅;
  • 能够感知组件(Fragment、Activity、Service)的生命周期;
  • 只有在组件出于激活状态(STARTED、RESUMED)才会通知观察者有数据更新

为什么需要LiveData

从LiveData具有的特点,我们就能联想到它能够解决我们遇到的什么问题。LiveData具有以下优点:

  • 能够保证数据和UI统一
     这个和LiveData采用了观察者模式有关,LiveData是被观察者,当数据有变化时会通知观察者(UI)。

  • 减少内存泄漏
     这是因为LiveData能够感知到组件的生命周期,当组件处于DESTROYED状态时,观察者对象会被清除掉。

  • 当Activity停止时不会引起崩溃
     这是因为组件处于非激活状态时,不会收到LiveData中数据变化的通知。

  • 不需要额外的手动处理来响应生命周期的变化
     这一点同样是因为LiveData能够感知组件的生命周期,所以就完全不需要在代码中告诉LiveData组件的生命周期状态。

  • 组件和数据相关的内容能实时更新
     组件在前台的时候能够实时收到数据改变的通知,这是可以理解的。当组件从后台到前台来时,LiveData能够将最新的数据通知组件,这两点就保证了组件中和数据相关的内容能够实时更新。

  • 针对configuration change时,不需要额外的处理来保存数据
      我们知道,当你把数据存储在组件中时,当configuration change(比如语言、屏幕方向变化)时,组件会被recreate,然而系统并不能保证你的数据能够被恢复的。当我们采用LiveData保存数据时,因为数据和组件分离了。当组件被recreate,数据还是存在LiveData中,并不会被销毁。

  • 资源共享
     通过继承LiveData类,然后将该类定义成单例模式,在该类封装监听一些系统属性变化,然后通知LiveData的观察者,这个在继承LiveData中会看到具体的例子。

LiveData使用

在了解LiveData定义和优点后,那它到底怎么应用呢?LiveData有几种使用方式:

  • 使用LiveData对象
  • 继承LiveData类
使用LiveData对象

使用LiveData对象主要有以下几个步骤:

  1. 创建保存特定数据类型的LiveData实例;
  2. 创建Observer对象,作为参数传入LiveData.observe()方法添加观察者;
  3. 更新Livedata对象存储的数据
创建LiveData实例

Android文档中建议LiveData配合ViewModel使用更加哦,其实也可以不使用ViewModel,但是一定要做到LiveData中保存的数据和组件分离

var mCurrentName: MutableLiveData = MutableLiveData()
创建Observer对象,添加观察者

在onCreate()方法中通过LiveData.observe()方法添加观察者,当数据变化时会通过回调方法通知观察者

 mNameViewModel.mCurrentName.observe(this, Observer { name: String? ->
            binding.nameText.text = name ?: ""
        })
更新LiveData中的数据

在上面我们已经订阅了LiveData数据变化,我们在xml中增加按钮来改变LiveData中的数据。

binding.nameBtn.addClickAction {
            mNameViewModel.mCurrentName?.value = "liveData"
        }

我们发现按钮点击,LiveData数据变化时,上面的lambda表达式中会收到更新的通知。

继承LiveData类

除了直接使用LiveDatad对象外,我们还可以通过集成LiveData类来定义适合特定需求的LiveData。下面继承LiveData类的例子,验证下LiveData的其中一个优点——资源共享。

class TestLiveData() : LiveData() {

    var mContextWeakReference: WeakReference? = null
    private constructor(context: Context) : this() {
        this.mContextWeakReference = WeakReference(context)
    }

    companion object {
        var shared: TestLiveData? = null
    }
    fun getInstance(context: Context): TestLiveData? {
        if (shared == null) {
            shared = TestLiveData(context)
        }
        return shared
    }

    /**
     * 当这个方法被调用时,
     * 表示LiveData的观察者数量从0变为了1,
     * 这时就我们的位置监听来说,就应该注册我们的时间监听了。
     */
    override fun onActive() {
        super.onActive()
        registerReceiver()
    }

    /**
     * 这个方法被调用时,
     * 表示LiveData的观察者数量变为了0,
     * 既然没有了观察者,也就没有理由再做监听,此时我们就应该将位置监听移除。
     */
    override fun onInactive() {
        super.onInactive()
        unregisterReceiver()
    }

    private fun registerReceiver() {
        val intentFilter = IntentFilter()
        intentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION)
        mContextWeakReference?.get()?.registerReceiver(mReceiver, intentFilter)
    }

    private fun unregisterReceiver() {
        mContextWeakReference?.get()?.unregisterReceiver(mReceiver)
    }


    private val mReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val action = intent.action
            if (WifiManager.RSSI_CHANGED_ACTION == action) {
                val wifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200)
                val wifiLevel = WifiManager.calculateSignalLevel(
                        wifiRssi, 4)
                shared?.setValue("wifiRssi = " + wifiRssi + "  wifiLevel = " + wifiLevel)
            }
        }
    }
}

TestLiveData是个继承了LiveData的单例类,在onActive()和onInactive()方法中分别注册和反注册Wifi信号强度的广播。然后在广播接收器中更新TestLiveData对象。在使用的时候就可以通过TestLiveData.getInstance()方法,然后通过调用observe()方法来添加观察者对象,订阅Wifi信息强度变化。

  • onActive(),此方法是当处于激活状态的observer个数从0到1时,该方法会被调用。
  • onInactive() ,此方法是当处于激活状态的observer个数从1变为0时,该方法会被调用。

时序图

Android架构组件-LiveData_第1张图片
LiveData时序图

LiveData主要涉及到的时序有三个:

  • 在Fragment/Activity中通过LiveData.observer()添加观察者(observer()方法中的第二个参数)。
  • 根据Fragment/Activity生命周期发生变化时,移除观察者或者通知观察者更新数据。
  • 当调用LiveData的setValue()、postValue()方法后,通知观察者更新数据。

改变LiveData数据

LiveData提供了两种改变数据的方法:setValue()和postValue()。区别是setValue()要在主线程中调用,而postValue()既可在主线程也可在子线程中调用。我们先看setValue()方法的具体实现:

@MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");//判断当前线程是否是主线程,不是主线程就抛出异常
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

再看下postValue()方法的具体实现:

protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        // 会在主线程中执行  mPostValueRunnable中的内容。
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            // 在主线程中调用setValue()方法
            setValue((T) newValue);
        }
    };

observe与observeForever

LiveData提供了两种添加观察者的方法:observeForever()、observe()。
查看源码:
observeForever

    @MainThread
    public void observeForever(@NonNull Observer observer) {
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        wrapper.activeStateChanged(true);//设置为true,观察者会一直受到数据的变化
    }
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);//notify数据
            }
        }

通过observeForever()添加观察者,观察者会一直受到数据的变化回到,而不是在组件处于STARTED和RESUMED状态下才会收到,因为这是LifecycleOwner对象就不再是组件了,而是ALWAYS_ON;另外通过该方法添加观察者后,要手动调用removeObserver()方法来停止观察者接收回调通知。

observe

@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        // mObservers可以理解成一个类似Map的容器,putIfAbsent()方法是判断容器中的observer(key)
        // 是否有已经和wrapper(value)关联,如果已经关联则返回关联值,否则关联并返回wrapper。
        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);//条件LifecycleOwner的生命周期观察者
    }

将LifecycleOwner对象和Observer对象封装成LifecycleBoundObserver对象。

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

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer 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);//区别observeForever是在DESTROYED时已帮removeObserver,不需手动remove
                return;
            }
            activeStateChanged(shouldBeActive());//在activity处于STARTED状态时通知监听者
        }

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

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

LiveData的转换

有时候有这样的需求,需要在LiveData将变化的数据通知给观察者前,改变数据的类型;或者是返回一个不一样的LiveData。

这里介绍一个类Transformations,它可以帮助完成上面的这些操作。

  • Transformations.map()

在LiveData数据的改变传递到观察者之前,在数据上应用一个方法:

var userLiveData: MutableLiveData = MutableLiveData()
/**
 * 需要在LiveData将变化的数据通知给观察者前,改变数据的类型
 * 直接赋值,source返回为null
 */
var userNameLiveData: LiveData = Transformations.map(userLiveData, { user ->
            user.userName
        })
@MainThread
    public static  LiveData map(@NonNull LiveData source,
            @NonNull final Function func) {
        final MediatorLiveData result = new MediatorLiveData<>();
        result.addSource(source, new Observer() {
            @Override
            public void onChanged(@Nullable X x) {
                result.setValue(func.apply(x));//改变时才设置值
            }
        });
        return result;
    }
  • Transformations.switchMap()

与Transformations.map()类似,只不过这里传递个switchMap()的方法必须返回一个LiveData对象。

@MainThread
    public static  LiveData switchMap(@NonNull LiveData trigger,
            @NonNull final Function> func) {
        final MediatorLiveData result = new MediatorLiveData<>();
        result.addSource(trigger, new Observer() {
            LiveData mSource;

            @Override
            public void onChanged(@Nullable X x) {
                LiveData newLiveData = func.apply(x);
                if (mSource == newLiveData) {
                    return;
                }
                if (mSource != null) {
                    result.removeSource(mSource);
                }
                mSource = newLiveData;
                if (mSource != null) {
                    result.addSource(mSource, new Observer() {
                        @Override
                        public void onChanged(@Nullable Y y) {
                            result.setValue(y);
                        }
                    });
                }
            }
        });
        return result;
    }

示例

var userNameLiveData2: LiveData =  Transformations.switchMap(userLiveData, { user ->
    var liveData: MutableLiveData = MutableLiveData()
    liveData.value = user.userName
    liveData
})

参考:

  • Android架构组件(二)——LiveData
  • Android官方架构组件介绍之LiveData

你可能感兴趣的:(Android架构组件-LiveData)