记录LiveData使用及原理
LiveData
一 使用方式:
添加依赖
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.7.0"
创建LiveData
val liveData = MutableLiveData<String>()
观察数据变化
liveData.observe(this) { data ->// 这里是数据变化时的回调(this 通常是 LifecycleOwner,如 Activity/Fragment)textView.text = data
}
更新数据
liveData.value = "新数据" // 主线程
liveData.postValue("异步新数据") // 任何线程
典型场景就是和ViewModel结合,做数据驱动界面更新。
二 LiveData原理讲解
1.生命周期感知
LiveData 通过感知 LifecycleOwner(Activity、Fragment)的生命周期,只在 owner 处于活跃状态(如 STARTED/RESUMED)时分发数据变更,owner 销毁后自动移除监听,避免内存泄漏。
2. 观察者模式
LiveData 内部维护一个 Observer 列表。当数据变化时(setValue/postValue),遍历所有活跃 Observer,回调其 onChanged 方法。
3. 数据分发机制
- 只有处于活跃生命周期的 Observer 才会收到数据
- 数据在主线程分发(postValue 会切到主线程)
4. 自动解绑
当 LifecycleOwner 进入 DESTROYED 状态,LiveData 自动移除对应的 Observer,无需手动解绑。
5. 粘性事件
新注册的 Observer,如果 LiveData 已有数据,会立即收到最新数据一次(即粘性事件)。
这个就更没啥说的了,就是一个观察者模式的应用,并且感知宿主也就是LifecycleOwner的生命周期,仅在活跃的时候进行数据分发。在宿主销毁的时候自动解绑。
ViewModel
创建ViewModel
public class MyViewModel extends ViewModel {private MutableLiveData<String> userName = new MutableLiveData<>();public LiveData<String> getUserName() {return userName;}public void setUserName(String name) {userName.setValue(name);}
}
在界面中获取ViewModel
public class MainActivity extends AppCompatActivity {private MyViewModel viewModel;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取 ViewModel 实例,生命周期与 Activity 相关联viewModel = new ViewModelProvider(this).get(MyViewModel.class);// LiveData 绑定 UI,自动感知生命周期viewModel.getUserName().observe(this, new Observer<String>() {@Overridepublic void onChanged(String name) {TextView textView = findViewById(R.id.textView);textView.setText(name);}});// 更新数据(如点击按钮)viewModel.setUserName("Copilot");}
}
二:ViewModel原理简述
viewModel与Activity生命周期绑定,但是不会因为界面重建而销毁,只有界面彻底销毁时才会销毁。它不持有activity的直接引用,值存储数据,降低内存泄漏的风险。
不想写了,真的不清楚写啥~ 能想到面试官问
为什么我们总是使用viewModel搭配LiveData使用?
因为它内置了 MutableLiveData 我们用LiveData保存数据,而viewModel在界面重建的时候不会销毁。而LiveData又可以感知生命周期,巴拉巴拉 扒拉扒拉 自己遍吧。他们就是很配,那有什么 为什么~
哦,对哦。有一个现实问题;
比如你的ViewModel 是绑定的Activity创建的,而你在Fragment上使用,会发现使用MutableLiveData 变更数据的时候又多次通知为什么?
这其实是ViewModel的作用域 和 LiveData粘性事件组合导致的。
- 如果你用
ViewModelProvider(this)
获取 ViewModel,this 是 Activity,则 ViewModel 作用域是整个 Activity。 - 在 Activity 下的多个 Fragment 中,使用同一个 ViewModel 实例(如
MainViewModel
),它们共享数据。 - LiveData 的 observe() 方法是“粘性”的:新注册的 Observer 会立即收到 LiveData 当前最新数据(即使之前已变化过)。
- 如果你在 Fragment 的 onCreateView/onViewCreated 每次都 observe,且 Fragment多次重建(如切换Tab或返回栈),每次都会收到最新数据一次。
- 当你调用
setValue
或postValue
,所有活跃 Observer(无论在 Activity 还是 Fragment)都会收到数据变化通知。
这其实是我搭建矿建的时候埋的一个坑,当时在BaseFragment中获取ViewModel的作用域是Fragment,但是我们有一个问我有什么方式可以优雅的Fragment之间传值吗?我当时脑子一热就直接把作用域改成了Activity,这样ViewModel作用域就是Activity,它持有的所有Fragment都可以互相传值。但是问题就是会触发多次。
解决办法是 魔改LiveData,消除粘性事件。比如 SingleLiveEvent
public class SingleLiveEvent <T> extends MutableLiveData<T> {private final AtomicBoolean mPending = new AtomicBoolean(false);@Overridepublic void observe(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer) {super.observe(owner, new Observer<T>() {@Overridepublic void onChanged(@Nullable T t) {if (mPending.compareAndSet(true, false)) {observer.onChanged(t);}}});}@MainThreadpublic void setValue(@Nullable T t) {mPending.set(true);super.setValue(t);}/*** Used for cases where T is Void, to make calls cleaner.*/@MainThreadpublic void call() {setValue(null);}
}
通过一个标记变量mPending
,只有在事件真正变更时才允许
面试官问你,LiveData和EventBus有什么区别 ,怎么选择使用
“LiveData 是 Jetpack 官方响应式数据持有者,能自动感知生命周期,防止内存泄漏,类型安全,适合 UI 层数据绑定。EventBus 是第三方事件总线库,不感知生命周期,需要手动管理注册和解注册,适合全局和组件间事件通信,但易滥用和管理混乱。一般推荐 UI 层用 LiveData,全局事件可选 EventBus,但要注意生命周期和内存管理。