LiveData使用和生命感知原理

你知道LiveData是如何做到感知生命周期的吗?

前言

使用LiveData有以下优势

  • 数据及时刷新:无论前台任务还是后台任务,只要当前页面处于活跃状态,就能马上刷新数据
  • 不会因 Activity 停止而导致崩溃:如果观察者的生命周期处于非活跃状态,则它不会接收任何 LiveData 事件。
  • 共享资源:您可以使用单例模式扩展 LiveData 对象以封装系统服务,以便在应用*享它们。
  • 不会发生内存泄漏:观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。

导入依赖

导入LiveData很简单

需要在项目根路径下的build.gradle文件中添加

allprojects {
    repositories {
        google()
        ....
    }
}

然后在module下添加依赖即可

dependencies {
    def lifecycle_version = "2.3.0"
    implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
}

如果提示

This project uses AndroidX dependencies, but the 'android.useAndroidX' property is not enabled. Set this property to true in the gradle.properties file and retry.

就在项目的根路径下创建新的文件gradle.properties 然后添加如下配置即可

android.useAndroidX=true
android.enableJetifier=true

LiveData用法

监听值变化

livedata可以单独使用,我们只需要创建一个LiveData对象,并观察其值的变化即可。

class MainActivity : AppCompatActivity() {
    lateinit var showText: Button;
    var liveData = MutableLiveData<String>()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        showText = findViewById(R.id.showText)
        // 传入LifecycleOwner,并观察livedata的值
        liveData.observe(this, Observer {
            // 显示更新后的值
            showText.text = it
        })
        liveData.value = "init"
    }
    // 点击回调事件,让Livedata更新值
    fun onMainThread(view: View) {
        liveData.value = "from main thread "
    }
    // 子线程更新livedata的值
    fun onWorkThread(view: View) {
        Thread {
            liveData.postValue("from work thread")
        }.start()
    }
    // 模拟后台耗时任务,回到activity重新显示最新的值
    override fun onStop() {
        super.onStop()
        Thread {
            Thread.sleep(1000)
            liveData.postValue("from back work thread")
        }.start()
    }
}

扩展LiveData

如果有一个观察者的生命周期处于 STARTEDRESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
    private val stockManager = StockManager(symbol)

    private val listener = { price: BigDecimal ->
        value = price
    }
    // LiveData进入活跃状态
    override fun onActive() {
        stockManager.requestPriceUpdates(listener)
    }
    // LiveData进入暂停状态
    override fun onInactive() {
        stockManager.removeUpdates(listener)
    }
}
  • LiveData 对象具有活跃观察者时,会调用onActive()方法。这意味着,您需要从此方法开始观察股价更新。
  • LiveData 对象没有任何活跃观察者时,会调用onInactive()方法。由于没有观察者在监听,因此没有理由与 StockManager 服务保持连接。

全局共享

我们可以在多个 Activity、Fragment 和 Service 之间共享LiveData对象。为此可以将 LiveData 类实现为一个单例

class StockLiveData : MutableLiveData<String>() {
    companion object {
        private const val TAG = "StockLiveData"
        // 声明一个单例
        private lateinit var instance: StockLiveData
        fun get(): StockLiveData {
            instance = if (::instance.isInitialized) instance else StockLiveData()
            return instance
        }
    }

    override fun onActive() {
        super.onActive()
        Log.d(TAG, "onActive: ")
    }

    override fun onInactive() {
        super.onInactive()
        Log.d(TAG, "onInactive: ")
    }
}

然后通过单例注册Observer

class MainActivity : AppCompatActivity() {
    lateinit var showText: Button;

    companion object {
        private const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        showText = findViewById(R.id.showText)
        // 传入LifecycleOwner,并观察livedata的值
        StockLiveData.get().observe(this, {
            // 显示更新后的值
            showText.text = it
        })
    }
}

以上就是livedata的基本用法。

跨线程更新原理

LiveData作为抽象类,我们是不能直接使用的,而MutableLiveData 其实只是Livedata的封装。其setValue与postValue均是调用了LiveData的接口。

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其实就是做了一件事情,更新mPendingData,切到主线程

public abstract class LiveData<T> {
    // 锁对象
    final Object mDataLock = new Object();
    // 用于标志数据是否被更新
    static final Object NOT_SET = new Object();
    // 用于临时存储更新后的值
    volatile Object mPendingData = NOT_SET;

    // 在主线程执行的runnable
    private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                // 将mPendingData置为未设置状态 
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    };
    ...
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            // 之前的值还没更新,就直接return
            return;
        }
        // 切到主线程
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
}

可以看出来,postValue最后也是调用了setValue

public abstract class LiveData<T> {
    ...
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        // 存储最新值
        mData = value;
        // 将值更新的事件通知观察者
        dispatchingValue(null);
    }
    
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            // 如果正在分发,就直接return
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            // setValue 更新的时候,initiator 为null,暂时忽略
            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;
    }
}

considerNotify 又是做啥的呢?

public abstract class LiveData<T> {
    ...
    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            // 观察者处于暂停状态,就忽略掉。等周期回调的时候触发
            return;
        }
        // 校验观察者的状态是否可以活跃,否则更新到睡眠状态
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        // 观察者上次获取到值的版本>= 当前的版本,就忽略,防止多次调用
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        // 更新观察者的值版本号,并调用onChanged回调
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }
}

到此,一次完整的事件通知就结束了,postValue顺带了setValue的实现,也是代码复用的体现。

现在回过头看看liveData的observe干了啥,想必读者也能猜出来了,就是注册一个观察者

public abstract class LiveData<T> {
    ...
    @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);
    }
}

感知周期原理

Lifecycle

在了解Livedata感知周期原理前,需要提一下Jetpack中的Lifecycle组件。

Lifecycle 是一个类,用于存储有关组件(如 Activity 或 Fragment)的生命周期状态的信息,并允许其他对象观察此状态。

组件(activity或者fragment)的周期与states的关系如下图
LiveData使用和生命感知原理
光看图可能会被比较懵,我们来看看代码

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        var data = LifeCycleListener(this.lifecycle)
        // 注册lifecycle的回调
        lifecycle.addObserver(data)
    }

    class LifeCycleListener(private val lifecycle: Lifecycle) : LifecycleObserver {
        // 标记对应周期回调的方法
        @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
        fun onCreate() {
            Log.d(TAG, "is onCreate: " + (lifecycle.currentState == Lifecycle.State.CREATED))
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        fun onStart() {
            Log.d(TAG, "is onStart: " + (lifecycle.currentState == Lifecycle.State.STARTED))
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        fun onResume() {
            Log.d(TAG, "is onResume: " + (lifecycle.currentState == Lifecycle.State.RESUMED))
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        fun onPause() {
            Log.d(TAG, "is onPause: " + (lifecycle.currentState == Lifecycle.State.STARTED))
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        fun onStop() {
            Log.d(TAG, "is onStop: " + (lifecycle.currentState == Lifecycle.State.CREATED))
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        fun onDestroy() {
            Log.d(TAG, "is onDestroy: " + (lifecycle.currentState == Lifecycle.State.DESTROYED))
        }
    }
}

对应的log如下
LiveData使用和生命感知原理
但这样需要定义很多方法,有一种更简便的实现

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 注册lifecycle的回调
        lifecycle.addObserver(LifecycleEventObserver())
    }
    
    class LifecycleWatcher : LifecycleEventObserver {

        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
            Log.d(TAG, "onStateChanged: lifecycle ${event.name} state ${event.targetState}")
        }
    }
}

LiveData使用和生命感知原理
LiveData正是通过这种方式监听activity的周期。

observe实现

LiveData在注册观察者的时候,创建了一个LifecycleBoundObserver 并注册到Lifecycle中。需要注意的是,一个Observer对应一个LifecycleOwner,

public abstract class LiveData<T> {
    ...
    @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);
    }
}

LifecycleBoundObserver是LiveData的内部类

    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) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) {
                // 目标已被销毁,就移除掉观察者
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
                prevState = currentState;
                // 通知State变化
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }
        ....
    }

看看ObserverWrapper的activeStateChanged方法

    private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

        void activeStateChanged(boolean newActive) {
            // 只有从活跃到暂停,或者暂停到活跃,才往下走
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            changeActiveCounter(mActive ? 1 : -1);
            if (mActive) {
                //  调用LiveData的更新值流程
                dispatchingValue(this);
            }
        }
    }

changeActiveCounter 方法主要保存当前状态,并判断是否要通知活跃变化

    void changeActiveCounter(int change) {
        int previousActiveCount = mActiveCount;
        mActiveCount += change;
        if (mChangingActiveState) {
            return;
        }
        mChangingActiveState = true;
        try {
            while (previousActiveCount != mActiveCount) {
                // call Active方法的条件:上次没有处于活跃的观察者(带有lifecycleOwner),并且当前有处于活跃的观察者
                boolean needToCallActive = previousActiveCount == 0 && mActiveCount > 0;
                // call Inactive方法的条件:上次有处于活跃的观察者(带有lifecycleOwner),并且当前没有处于活跃的观察者
                boolean needToCallInactive = previousActiveCount > 0 && mActiveCount == 0;
                previousActiveCount = mActiveCount;
                if (needToCallActive) 
                    // 通知当前处于活跃状态
                    onActive();
                } else if (needToCallInactive) {
                    // 通知当前处于暂停状态
                    onInactive();
                }
            }
        } finally {
            mChangingActiveState = false;
        }
    }

小结:LiveData主要通过监听lifecycleOwner的周期,来实现粘性事件

解决内存泄漏原理

LiveData是如何保证不发生内存泄漏的呢?

主要是在周期遭到销毁后进行自我清理,切断观察者与activity等的引用关系

        // 生命周期的回调
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) {
                // 目标已被销毁,就移除掉观察者,断开引用关系
                removeObserver(mObserver);
                return;
            }
            .....
        }

但对于没有注册lifecycleOwer的观察者,LiveData就无法主动移除了

observeForever实现

observeForever的实现与observe有点类似,只是无法感知周期。

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

而AlwaysActiveObserver的实现也比较简单

    private class AlwaysActiveObserver extends ObserverWrapper {

        AlwaysActiveObserver(Observer<? super T> observer) {
            super(observer);
        }
        // 永远处于活跃状态
        @Override
        boolean shouldBeActive() {
            return true;
        }
    }

这也意味着,我们需要手动调用一下removeObserver,防止内存泄漏

class MainActivity : AppCompatActivity() {
    var observer = Observer<String> {
        Log.d(TAG, "no lifecycle Observer: value => $it")
    }
    override fun onResume() {
        super.onResume()
        liveData.observeForever(observer)
    }
    override fun onStop() {
      super.onStop()
      liveData.removeObserver(observer)
    }
}

合并多个源

如果想同时监听多个数据的变化怎么办?可以使用 MediatorLiveData

用法如下

 LiveData liveData1 = new LocalLiveData();
 LiveData liveData2 = new RemoteLiveData();

 MediatorLiveData liveDataMerger = new MediatorLiveData<>();
 liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
 liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));

后记

知识比较零散,这里做了一个总结

  • livedata采用观察者模式,内部通过监听生命周期、版本号方式维护数据,保证能及时、有效的刷新。
  • Livedata可以配个viewModel,实现MVVM架构。
  • call Active方法的条件:上次没有处于活跃的观察者(带有lifecycleOwner),并且当前有处于活跃的观察者。
  • call Inactive方法的条件:上次有处于活跃的观察者(带有lifecycleOwner),并且当前没有处于活跃的观察者。
  • LiveData内部通过监听组件周期,自动注销观察者,防止内存泄漏。
  • 在跨线程更新数据时,通过volatile和加锁方式来保证数据的一致性。
  • 内部使用SafeIterableMap 来维护Observer,可以在迭代Observer的同时将其移除掉。
  • 一个Observer对应一个lifecycleOwner,否则将报错。
上一篇:php设计模式之观察者模式


下一篇:Android lifecyle 源码解剖,android应用开发