Jetpack之LiveData分析

LiveData是Android Jetpack架构组件的一部分,它能在底层数据变化时通知UI更新,尤其适用于MVVM架构。LiveData具备生命周期感知能力,能根据Activity/Fragment的状态自动管理自身,并防止内存泄露。它提供setValue和postValue方法在主线程和子线程更新数据,通过LifecycleBoundObserver和TaskExecutor实现观察者模式和任务调度。

概述

官方doc

LiveData属于Jetpack的架构组件,目的在于当底层数据发生更改的时候可以通知到上层UI进行更新,配合MVVM架构使用,是非常舒服的。

个人对它的理解分成两部分:

1.LivaData=Live+Data,Live是指它是有生命的,或者说可以感知到生命周期的变化。Data是指它的本质还是一个数据存储相关的类。

2.实际的实现就是观察者模型,LiveData的观察者(如我们在observe方法的时候传入的匿名observer对象)是与Lifecycle对象(通常是Activity/Fragment)绑定在一起的,在其处于活跃状态(比如对应的Activity处于started,resumed)的时候,LiveData(被观察者)的更新将会通知到观察者(回调到onChanged方法)。

用它的好处:①最重要的,LiveData作为被观察者可以感知到观察者(Activity/Fragment)的生命周期,自行去管理自身的生命周期。②如上说的,只有当Activity或者Fragment处于活跃状态的时候,才能收到LiveData数据更新的通知,这可以确保,数据发生更新的时候,UI的状态也是可以更新的。③可以根据观察者的生命周期变化,在观察者销毁后进行自我清理,避免内存泄露。④当界面重新恢复到活跃状态或者重新创建的时候,会立即接收到最新的数据。

用法

见官方文档。

分析:

LiveData本身是一个抽象类,在Jetpack组件中唯一的子类是MutableLiveData。公开了两个方法setValue和postValue。两个方法用来更新LiveData的值,前者只能在主线程中调用,后者可以在子线程中调用,通过Handler消息机制,通知到主线程更新。

在这分析这两个方法之前,先来看下,观察者如何订阅LiveData,即LiveData的observe方法:

// 第一个参数是Lifecycle的持有者,比如Activity、Fragment
// 第二个参数是观察者对象,我们一般就是直接创建一个匿名对象
public void observe(LifecycleOwner owner, Observer<T> observer) {
    // 如果观察者在订阅LiveData的时候已经处于destoryed状态,直接跳过订阅
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        return;
    }
    // 将owner与observer封装成LifecycleBoundObserver对象,这个对象主要封装了
    // 对Lifecycle的生命状态的赋值操作以及状态改变时对观察者进行取消订阅的操作。
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    // mObservers是一个支持在迭代的过程中进行更改的链表结构(存放Entry<K,V>),
    // 存放的是观察者和上面的包装对象,注意如果链表已经存放了某一个key为observer的entry
    // 不是去更新这个entry而是直接返回value。
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    // 如果返回的value不是null,然后去确定一下,这个observer的owner与新传入的owner
    // 是不是一致的,如果一致,就表示这个观察者已经绑定了某一个owner,不能重复绑定
    if (existing != null && !existing.isAttachedTo(owner)) {
        throw new IllegalArgumentException( "Cannot add the same observer"
 + " with different lifecycles" );
    }
    // 如果返回的value不是null,但是也没有进入上面的异常抛出
    // 那就是这一次绑定的owner是一样的,没有必要重复绑定相同的owner
    if (existing != null) {
        return;
    }
    // 为owner添加生命周期观察者,这样wrapper,或者说observer就可以感知到
    // owner(Activity/Fragment)的生命周期,当其生命周期发生变化的时候,
    // 可以调用到wrapper的onStateChanged,去更新活跃状态
    owner.getLifecycle().addObserver(wrapper);
}

LifecycleBoundObserver的onStateChanged方法:

public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
    // 如果组件的生命周期是销毁状态,那么会自动的removeObserver移除观察者,
    // 从而解除observer对LifecyclerOwner的引用,避免内存泄露的发生
    if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
        removeObserver(mObserver);
        return;
    }
    // 如果不是Destoryed状态,那么当Owner的生命周期变化时,会去更新到LiveData的活跃状态
    activeStateChanged(shouldBeActive());
}

上面是对LiveData的生命状态相关的分析,然后看下对LiveData的赋值操作。

setValue:

protected void setValue(T value) {
    assertMainThread( "setValue" );// 非主线程IllegalStateException
    mVersion++;// 标记当前data的版本
    mData = value;// 赋值data
    dispatchingValue(null);
}

setValue调用的dispatchingValue,传入的是null:

private void dispatchingValue(@Nullable ObserverWrapper initiator) {
    // 如果正在分发value,则直接return
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            // 后续
            considerNotify(initiator);
            initiator = null;
        } else {
            // 遍历mObservers链表,去决定是否需要通知观察者更新
            for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

considerNotify:

private void considerNotify(ObserverWrapper observer) {
    // 如果观察者不处于活跃状态,则直接跳过
    if (!observer.mActive) {
        return;
    }
    // 可能出现Owner的生命周期变化了,但是LiveData并没有收到相关通知,
    // 这里主动去获取Owner的当前(最新)生命状态
    // shouldBeActivie在这两种情况下返回true
    // STARTED:对应的就是Activity生命周期的调用onStart之后,onPause之前
    // RESUMED: onResume调用之后
    if (!observer.shouldBeActive()) {
        // 如果处于Owner的生命状态不活跃,这里更新下
        observer.activeStateChanged(false);
        return;
    }
    // 如果最新的数据版本不大于上一次变动的版本,就是没变化,那就直接return
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    // 更新上一次变动的版本值
    observer.mLastVersion = mVersion;
    // 会掉到observer的onChanged方法,传入新的data
    //也就是我们在订阅LiveData的时候,传入的匿名对象重写的onChanged方法
    // 到这里,观察者就收到了LiveData的数据变动的通知。
    observer.mObserver.onChanged((T) mData);
}

postValue:

postValue用于在子线程通知主线程livedata发生了变化,代码如下:

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        // mPendingData
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    // 将mPostValueRunnable这个任务抛到主线程执行
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

先看下mPostValueRunnable:

private final Runnable mPostValueRunnable = new Runnable() {
    @Override
    public void run() {
        // 在主线程中完成data的更新
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            // 然后恢复mPendingData为未设置状态
            // 其实mPendingData的作用就是辅助确保data的更新是在主线程中进行
            mPendingData = NOT_SET;
        }
        // postValue最终调用的也是setValue
        setValue((T) newValue);
    }
};

上面还有一点ArchTaskExecutor,这是Jetpack架构中比较独立的一个部分,看下一点:

jetpack-livedata-2.png

TaskExecutor是抽象基类,主要定义了分别在子线程池和主线程处理Runnable的能力。

DefaultTaskExecutor是TaskExecutor的默认实现:

public class DefaultTaskExecutor extends TaskExecutor {
    private final Object mLock = new Object();
    // IO线程池是固定数量为2的线程池
    private ExecutorService mDiskIO = Executors.newFixedThreadPool(2);
    @Nullable
    private volatile Handler mMainHandler;
    @Override
    public void executeOnDiskIO(Runnable runnable) {
        mDiskIO.execute(runnable);
    }
    @Override
    public void postToMainThread(Runnable runnable) {
        // runnable通过关联主线程的Handler,post回主线程执行
        if (mMainHandler == null) {
            synchronized (mLock) {
                if (mMainHandler == null) {
                    mMainHandler = new Handler(Looper.getMainLooper());
                }
            }
        }
        mMainHandler.post(runnable);
    }
    @Override
    public boolean isMainThread() {
        return Looper.getMainLooper().getThread() == Thread.currentThread();
    }
}

ArchTaskExecutor也是TaskExecutor的实现,与DefaultTaskExecutor的不同在于,ArchTaskExecutor的所有对任务的处理都是通过mDelegate这个TaskExecutor的代理对象来完成的,通过ArchTaskExecutor的set方法,客户端可以通过继承TaskExecutor的方式,实现自己的Runnable任务处理逻辑。

@NonNull
private TaskExecutor mDelegate;// 默认实现就是mDefaultTaskExecutor
@NonNull
private TaskExecutor mDefaultTaskExecutor;// DefaultTaskExecutor实例
<think>我们被要求提供一个在Jetpack Compose中使用LiveData的简单示例代码。根据引用[4]的建议,我们应该将LiveData放在ViewModel中,并且Google推荐使用ViewModel+LiveData的方式。 在Jetpack Compose中,我们可以使用`observeAsState`扩展函数来观察LiveData,并将LiveData转换为Compose中的State,这样当LiveData的数据变化时,Compose就会自动重组使用该状态的UI部分。 下面是一个简单的示例,展示如何在Jetpack Compose中使用LiveData: 1. 首先,添加必要的依赖(根据引用[3]中提到,需要添加LiveData和ViewModel的依赖,但这里我们主要关注Compose中使用的依赖): - 对于Compose,我们需要使用`androidx.compose.runtime:runtime-livedata`中的扩展函数。 2. 创建ViewModel,其中包含一个LiveData对象。 3. 在Composable函数中,使用`viewModel()`获取ViewModel实例,然后使用`observeAsState`来观察LiveData。 示例代码如下: ```kotlin import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.material.Text import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewmodel.compose.viewModel // 定义ViewModel class MyViewModel : ViewModel() { // 创建一个LiveData,初始值为0 private val _counter = MutableLiveData(0) val counter: LiveData<Int> get() = _counter fun increment() { _counter.value = (_counter.value ?: 0) + 1 } } // 在Composable中使用 @Composable fun CounterScreen(viewModel: MyViewModel = viewModel()) { // 将LiveData转换为State,当LiveData变化时,会重组Text val count by viewModel.counter.observeAsState() Column { Text(text = "计数: $count") Button(onClick = { viewModel.increment() }) { Text("增加") } } } ``` 在这个例子中: - 我们创建了一个`MyViewModel`类,它继承自`ViewModel`,其中包含一个`MutableLiveData`用于计数,并暴露为不可变的`LiveData`。 - 在`CounterScreen`这个Composable函数中,我们通过`viewModel()`获取`MyViewModel`的实例(默认使用ViewModelProvider来获取或创建)。 - 使用`observeAsState()`将`counter`这个LiveData转换为Compose中的状态。这样,每当LiveData的值改变时,Compose就会重新组合使用`count`的地方。 - 我们显示当前的计数值,并提供一个按钮来增加计数。 注意:在Compose中,我们使用`by`委托来获取状态值,这样我们可以直接使用`count`。当点击按钮时,调用ViewModel的`increment`方法,该方法会更新LiveData的值,从而触发UI更新。 另外,由于LiveData具有生命周期感知能力,Compose的`observeAsState`会在Composable的生命周期内自动开始和停止观察LiveData,因此无需担心内存泄漏。 这个示例展示了在Jetpack Compose中集成LiveData的基本方法,它结合了ViewModel和LiveData的优势,同时利用Compose的状态管理来实现响应式UI。 §§相关问题§§ 1. 在Jetpack Compose中使用LiveData时,如何处理空值或初始化状态? 2. 除了LiveDataJetpack Compose中还有哪些状态管理方式? 3. 如何测试使用LiveData和ViewModel的Compose界面?</think>### Jetpack Compose 中使用 LiveData 的示例 在 Jetpack Compose 中使用 LiveData 需要结合 `observeAsState()` 扩展函数,它可以将 LiveData 转换为 Compose 的状态对象。以下是完整示例: ```kotlin // 1. 添加依赖 (build.gradle) dependencies { implementation "androidx.compose.runtime:runtime-livedata:1.3.0" implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1" } // 2. 创建 ViewModel 和 LiveData class UserViewModel : ViewModel() { // 创建 LiveData 对象 private val _userName = MutableLiveData("初始用户名") val userName: LiveData<String> = _userName // 更新 LiveData 的方法 fun updateName(newName: String) { _userName.value = newName } } // 3. 在 Composable 中使用 @Composable fun UserProfileScreen(viewModel: UserViewModel = viewModel()) { // 将 LiveData 转换为 State val userNameState by viewModel.userName.observeAsState("加载中...") Column( modifier = Modifier.padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { // 显示 LiveData 的值 Text( text = "当前用户名: $userNameState", style = MaterialTheme.typography.h6, modifier = Modifier.padding(bottom = 16.dp) ) // 更新 LiveData 的按钮 Button(onClick = { viewModel.updateName("用户_${Random.nextInt(100)}") }) { Text("更新用户名") } } } ``` #### 关键点说明: 1. **ViewModel 集成**:通过 `viewModel()` 函数获取 ViewModel 实例,确保配置更改时数据不丢失[^4] 2. **状态转换**:`observeAsState()` 将 LiveData 转换为 Compose 的 `State` 对象 3. **自动更新**:当 LiveData 值变化时,使用该状态的 Composable 会自动重组 4. **生命周期感知**:Compose 会自动处理观察者的注册和注销,避免内存泄漏[^3] #### 效果: - 初始显示 "当前用户名: 初始用户名" - 点击按钮后用户名会随机更新为 "用户_XX" 格式 - UI 会自动刷新显示最新值 #### 最佳实践: 1. 始终通过 ViewModel 暴露 LiveData,而不是直接操作 MutableLiveData[^4] 2. 对于复杂数据结构,使用 `observeAsState(initial)` 指定初始值 3. 结合 `LaunchedEffect` 处理异步操作: ```kotlin LaunchedEffect(Unit) { viewModel.userData.collect { data -> // 处理数据流更新 } } ```
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值