Jetpack LiveData

1. 什么是LiveData?

  • LiveData 是一种可观察的数据持有者,通常用于在 Android 应用中以生命周期感知的方式更新UI。
  • 它是生命周期感知的,意味着它只会通知处于活跃生命周期状态(如 STARTED 或 RESUMED)的观察者。
  • LiveData 通常与 ViewModel 结合使用,用于将 UI 与数据分离。

2. LiveData 的使用场景

  • 数据驱动 UI:当数据发生变化时,自动更新UI,例如从数据库或网络获取数据后更新界面。
  • 事件感知:使用 LiveData 通知 UI 层某些事件的发生,例如网络请求完成或数据库更新。
  • 跨组件通信:在多个 Fragment 或 Activity 之间共享数据,确保数据的一致性。

3. 使用

object MyLiveData {
    val info1: MutableLiveData<String> by lazy { MutableLiveData<String>() }
}
class LiveDataActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)

        val textview: TextView = findViewById(R.id.livedata_textview)

        // 1 activity 是观察者
        MyLiveData.info1.observe(this) {
            textview.text = it
        }

        // 完整写法 new Observer onChanged
//        MyLiveData.info1.observe(this, object : Observer{
//            override fun onChanged(value: String) {
//                println("activity 2 收到消息:$value")
//            }
//        })

        // 2 触发数据改变
        MyLiveData.info1.value = "default" // setValue 主线程

        thread {
            Thread.sleep(3000)
            MyLiveData.info1.postValue("3 秒钟后,修改了哦") // postValue 子线程
        }

        thread {
            Thread.sleep(6000)
            MyLiveData.info1.postValue("6 秒钟后,修改了哦") // postValue 子线程
        }
    }
}

4. 源码分析

  • 核心类
    • LiveData:核心类,负责管理数据和观察者。
    • MutableLiveData:LiveData 的子类,提供了 setValue() 和 postValue() 方法,允许外部修改数据。
    • Observer:观察者接口,用于接收数据更新。
    • LifecycleOwner:生命周期所有者(如 Activity 或 Fragment),LiveData 通过它感知生命周期状态。

(1)观察者管理

我们都是调用 LiveData.observe 方法观察数据的变化。

 		MyLiveData.info1.observe(this, object : Observer<String>{
            override fun onChanged(value: String) {
                println("activity 2 收到消息:$value")
            }
        })

从 observe 函数入手,看它的逻辑。

	// LiveData.java
	@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    	// 代码1 
        assertMainThread("observe");
        // 代码2 检查生命周期状态
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        // 代码3 将观察者包装为 LifecycleBoundObserver
        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;
        }
        // 代码4 将观察者与生命周期绑定
        owner.getLifecycle().addObserver(wrapper);
    }

observe函数的第一个参数 LifecycleOwner,属于被观察者。Fragment或Activity的父类都继承了 LifecycleOwner 接口,而 LifecycleOwner 可获取到组件的 Lifecycle。所以 LiveData 通过 observe() 方法将观察者与组件的生命周期绑定了。

代码1:observe() 方法要求必须是在主线程调用。

代码2:接着判断当前是否是销毁状态,如果是就直接 return。

代码3:创建一个 LifecycleBoundObserver 对象,它是 ObserverWrapper 子类,可以感知宿主的生命周期。

调用 mObservers.putIfAbsent(observer, wrapper) 将 observe 和 wrapper 分别作为 key 和 value 存入 Map 中,putIfAbsent()方法会判断如果 value 已经能够存在,就返回,否则返回null。 如果返回existing为null,说明以前没有添加过这个观察者,就将LifecycleBoundObserver 作为宿主生命周期的观察者。

代码4:将观察者与生命周期绑定

(2)生命周期感知

接着看一下 LifecycleBoundObserver 逻辑:

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

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

		// 代码1 判断当前状态是否是存活状态STARTED,RESUMED。
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

		// 代码2 宿主每个生命周期执行时回调的函数
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            // 代码3 如果当前状态是DESTORYED,会解除所有观察者
            if (currentState == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
            // 代码4 判断当前状态和上个状态是否一致,不一致的话调用  activeStateChanged(shouldBeActive())
            while (prevState != currentState) {
                prevState = currentState;
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

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

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }
		void activeStateChanged(boolean newActive) {
			// 代码5
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            // 代码6
            changeActiveCounter(mActive ? 1 : -1);
            if (mActive) {
            	// 代码7
                dispatchingValue(this);
            }
        }

代码1,判断当前状态是否是存活状态STARTED,RESUMED。

代码2,宿主每个生命周期执行时回调的函数。
在分析 Lifecycle 源码时,我们看到过 LifecycleRegistry 中的同步方法 sync() 中,backwardPass 和 forwardPass,都调用了 observer.dispatchEvent() 分发生命周期事件。也就是说每个生命周期事件都会触发dispatchEvent(),然后调用 mLifecycleObserver.onStateChanged(owner, event),这里就会触发 LiveData 的 LifecycleBoundObserver 中 onStateChanged()。

代码3,每个生命周期回调到这里都会判断当前的状态是否 DESTROYED,如果是就移除所有的观察者,并return。

代码4,否则,判断当前状态和上个状态是否一致,不一致的话调用 activeStateChange(shouldBeActive()),然后调用changeActiveCounter(mActive)。

代码5,判断组件状态是否发生了变化。如果发生了变化,接着判断 mActive 状态。

代码6,当mActive是true时,会调用onActive()空函数,由外界实现。是false时,会调用onInactive()空函数,由外界实现。

代码7,做完这些之后,当 mActive 存活时,会继续执行 dispatchingValue(initiator),进行数据分发,后面再继续看。

(3)数据存储与更新

看完了观察者的逻辑之后,我们接着看LiveData 是怎么通知观察者的?

  • LiveData 的核心数据存储在一个泛型变量中:
private volatile Object mData;
  • 数据更新是我们调用 LiveData 的 setValue() 或 postValue() 触发的。

setValue()

 @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++; // 数据版本号增加
        mData = value;
        dispatchingValue(null); // 通知观察者
    }

setValue() 必须在主线程调用,先进行版本号加1,然后调用 dispatchingValue(null) 方法。

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() ,可以在后台线程调用,通过Handler从子线程切换到主线程后,再调用 setValue()。

(4)数据分发

了解了数据更新触发的逻辑后,接着看数据分发通过 dispatchingValue() 方法的实现:

	void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            // 代码1
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
            	// 代码2 遍历观察者
                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 void considerNotify(ObserverWrapper observer) {
		// 代码3 检测当前状态是否是活跃状态
        if (!observer.mActive) {
            return;
        }
        // 代码4 再次循环检测当前是否存活,不存活就等待。可以检测当前页面突然可见的状况。
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        // 代码5 下面是粘性事件。判断观察者的版本和被观察者的版本,如果被观察者的版本小于观察者,就走onChange(mData)分发数据。
        // 去除粘性:反射修改mLastVersion 让相等,直接return,不走后面dispatch
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        // 代码6
        observer.mObserver.onChanged((T) mData);
    }

代码1,dispatchingValue() 参数传 null 和不传 null 的区别是,如果传null,会通知所有的观察者。否则,只会通知传入的观察者。

代码2,遍历所有的观察者,也就是我们上面说的 LifecycleBoundObserver,调用 considerNotify() 方法。

代码3,检测当前状态是否是活跃状态。

代码4,再次循环检测当前是否存活,不存活就等待。可以检测当前页面突然可见的状况。

代码5,是粘性事件。判断观察者的版本和被观察者的版本,如果被观察者的版本小于观察者,就走onChange(mData)分发数据。
去除粘性:反射修改mLastVersion 让相等,直接return,不走后面dispatch。

代码6,observer.mObserver 是我们调用 LiveData 的 observe 方法传入的 Observer,然后调用 onChange(value) ,将更新的数据回调给我们自己的 onChange 中,实现了数据的更新。

5. 去除粘性的 UnPeekLiveData 实现

  • 背景:当先触发了数据更新后,再去订阅才会有粘性数据这种说法。如果LiveData默认的粘性会导致bug,才需要去除粘性(粘性也有数据倒灌说法)。一般情况下,先订阅,后 setValue() 更新数据,不会有这种问题。
  • 粘性导致的 bug:比如想只关心订阅之后的数据变化,订阅之前的历史数据不关心,粘性会导致历史数据带进来。
  • 实现思路:通过 hook 修改 LiveData 的 observer 方法里的 mLastVersion,将 mVersion 赋值给 mLastVersion
  • 实现:
class UnPeekLiveData<T> : MutableLiveData<T>() {
    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        super.observe(owner, observer)
        hook(observer)
    }

    private fun hook(observer: Observer<in T>) {
        val liveDataClass = LiveData::class.java
        try {
            //获取field private SafeIterableMap, ObserverWrapper> mObservers
            val mObservers = liveDataClass.getDeclaredField("mObservers")
            mObservers.isAccessible = true
            //获取SafeIterableMap集合mObservers
            val observers = mObservers[this]
            val observersClass: Class<*> = observers.javaClass
            //获取SafeIterableMap的get(Object obj)方法
            val methodGet = observersClass.getDeclaredMethod("get", Any::class.java)
            methodGet.isAccessible = true
            //获取到observer在集合中对应的ObserverWrapper对象
            val objectWrapperEntry = methodGet.invoke(observers, observer)
            var objectWrapper: Any? = null
            if (objectWrapperEntry is Map.Entry<*, *>) {
                objectWrapper = objectWrapperEntry.value
            }
            if (objectWrapper == null) {
                throw NullPointerException("ObserverWrapper can not be null")
            }
            //获取ObserverWrapper的Class对象  LifecycleBoundObserver extends ObserverWrapper
            val wrapperClass: Class<*>? = objectWrapper.javaClass.superclass
            //获取ObserverWrapper的field mLastVersion
            val mLastVersion = wrapperClass!!.getDeclaredField("mLastVersion")
            mLastVersion.isAccessible = true
            //获取liveData的field mVersion
            val mVersion = liveDataClass.getDeclaredField("mVersion")
            mVersion.isAccessible = true
            val mV = mVersion[this]
            //把当前ListData的mVersion赋值给 ObserverWrapper的field mLastVersion
            mLastVersion[objectWrapper] = mV
            mObservers.isAccessible = false
            methodGet.isAccessible = false
            mLastVersion.isAccessible = false
            mVersion.isAccessible = false
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

6. 其他

6.1 LiveData 的生命周期感知特性是如何实现的?

  • LiveData 通过 LifecycleOwner(如 Activity 或 Fragment)来感知生命周期状态。
  • 它会在 LifecycleOwner 处于活跃状态时通知观察者,而在 LifecycleOwner 处于非活跃状态时停止更新。
  • 这种机制避免了内存泄漏和无效的 UI 更新。

6.2 LiveData 和 MutableLiveData 的区别是什么?

  • LiveData 是不可变的,只能通过观察来获取数据,不能直接修改。
  • MutableLiveData 是 LiveData 的子类,提供了 setValue() 和 postValue() 方法,允许在外部修改数据。

通常,MutableLiveData 用于 ViewModel 中,而 LiveData 暴露给 UI 层,以确保数据的安全性。

6.3 LiveData 的 setValue() 和 postValue() 有什么区别?

  • setValue():必须在主线程中调用,用于同步更新数据。
  • postValue():可以在后台线程中调用,它会将更新操作切换到主线程执行。

如果需要从后台线程更新 LiveData,应该使用 postValue()。

6.4 LiveData 和 RxJava 的区别是什么?

(1)LiveData:

  • 简单易用,专为 Android 设计,具有生命周期感知能力。
  • 适合处理与 UI 相关的数据流。

(2)RxJava:

  • 功能更强大,支持复杂的异步操作和流式处理。
  • 需要手动管理生命周期,否则可能导致内存泄漏。

选择依据:如果只是简单的 UI 更新,LiveData 更合适;如果需要复杂的异步操作,RxJava 更强大。

6.5 如何在 LiveData 中进行数据转换?

  • 可以使用 Transformations.map() 和 Transformations.switchMap() 对 LiveData 进行数据转换。
  • map():用于对 LiveData 的值进行简单的转换。
  • switchMap():用于根据 LiveData 的值返回另一个 LiveData。

如:

val userLiveData: LiveData<User> = ...
val userNameLiveData: LiveData<String> = Transformations.map(userLiveData) { user ->
    user.name
}

6.6 LiveData 如何与 Room 数据库一起使用?

  • Room 可以直接返回 LiveData 类型的查询结果。
  • 当数据库中的数据发生变化时,Room 会自动更新 LiveData,从而触发 UI 更新。

如:

@Dao
interface UserDao {
    @Query("SELECT * FROM user")
    fun getUsers(): LiveData<List<User>>
}

6.7 LiveData 的缺点是什么?

  • 功能相对简单,不适合复杂的异步操作。
  • 不支持背压(backpressure)处理。
  • 与 RxJava 或 Kotlin Flow 相比,功能较为有限。

6.8 LiveData 和 StateFlow 的区别是什么?

(1)LiveData:

  • 专为 Android 设计,具有生命周期感知能力。
  • 适合简单的 UI 状态管理。

(2)StateFlow:

  • 是 Kotlin Flow 的一部分,功能更强大。

  • 需要手动管理生命周期,但可以与协程无缝集成。

选择依据:如果项目已经使用协程,StateFlow 是更好的选择;否则,LiveData 更简单易用。

6.9 LiveData 如何与 ViewModel 结合使用?

  • ViewModel 用于存储和管理与 UI 相关的数据。
  • LiveData 用于将 ViewModel 中的数据暴露给 UI 层。

如:

class MyViewModel : ViewModel() {
    private val _data = MutableLiveData<String>()
    val data: LiveData<String> get() = _data

    fun updateData(newValue: String) {
        _data.value = newValue
    }
}

6.10 LiveData 的 observe() 和 observeForever() 有什么区别?

  • observe():需要传入 LifecycleOwner,只有在其生命周期处于活跃状态时才会收到更新。
  • observeForever():不需要 LifecycleOwner,无论生命周期状态如何,都会收到更新。
  • 注意:observeForever() 需要手动移除观察者,否则可能导致内存泄漏。

observe() 在源码分析时,我们已经看过了。

接下来看一下 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);
    }

	void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            changeActiveCounter(mActive ? 1 : -1);
            if (mActive) {
                dispatchingValue(this);
            }
        }
	private class AlwaysActiveObserver extends ObserverWrapper {

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

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

可以发现观察者的封装是 AlwaysActiveObserver,在 AlwaysActiveObserver 中 shouldBeActive() 永远返回的是 true。无论生命周期状态如何,都会收到更新。

6.11 LiveData 如何处理配置变化(如屏幕旋转)?

  • LiveData 与 ViewModel 结合使用时,ViewModel 会在配置变化后继续存在。
  • LiveData 会重新连接到新的UI 组件,并立即发送最新的数据,确保 UI 状态一致。

6.12 LiveData 如何实现数据共享?

可以通过将 LiveData 定义在 ViewModel 中,并在多个 Fragment 或 Activity 之间共享同一个 ViewModel 实例。

如:ShareViewModel

val viewModel = ViewModelProvider(activity).get(SharedViewModel::class.java)
viewModel.sharedData.observe(this, Observer { data ->
    // 更新 UI
})

6.13 LiveData 的线程安全性?

LiveData 通过以下机制保证线程安全:

  • setValue() 必须在主线程调用。
  • postValue() 通过 Handler 将更新操作切换到主线程。
  • 观察者的添加和移除通过 synchronized 块保证线程安全。

6.14 LiveData 如何避免内存泄漏?

  • LiveData 是生命周期感知的,它会自动清理与已经销毁的 LifecycleOwner 关联的观察者。
  • 当 Activity 或 Fragment 被销毁时,LiveData 会自动移除观察者,从而避免内存泄漏。

总结

  • LiveData 的核心原理是通过 LifecycleOwner 感知生命周期状态,确保数据更新只发生在活跃状态。
  • 它通过 ObserverWrapper 和 LifecycleBoundObserver 管理观察者,并通过 dispatchingValue() 方法分发数据。
  • LiveData 的设计简单高效,适合处理与 UI 相关的数据流,但在复杂场景下可能不如 RxJava 或Kotlin Flow 灵活。

你可能感兴趣的:(JetPack,android)