尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Android随笔-LiveData

Android随笔-LiveData LiveData 详解一句话定义LiveData 是 Android Jetpack 提供的一个可观察的数据持有类特点是能感知生命周期——它只会在 Activity/Fragment 处于活跃状态STARTED或RESUMED时才向观察者推送数据组件销毁时自动清理从而避免内存泄漏和空指针崩溃。一、核心特性特性说明生命周期感知自动跟踪LifecycleOwnerActivity/Fragment的状态只在活跃时分发数据自动清理当LifecycleOwner进入DESTROYED状态时自动移除 Observer无需手动 unregister始终保持最新数据新注册的 Observer 会立即收到最近一次的数据粘性特性配置变更存活配合ViewModel使用屏幕旋转等配置变更后数据不丢失主线程安全setValue()必须在主线程postValue()可在任意线程调用二、基本使用2.1 创建与更新// ViewModel 中定义privateMutableLiveDataStringnameLiveDatanewMutableLiveData();// 主线程同步更新nameLiveData.setValue(张三);// 子线程异步更新内部自动切到主线程newThread(()-{nameLiveData.postValue(李四);}).start();2.2 观察数据// Activity 中观察viewModel.getName().observe(this,newObserverString(){OverridepublicvoidonChanged(Stringname){textView.setText(name);// 数据变化时自动执行}});// 或者 Lambda 写法viewModel.getName().observe(this,name-{textView.setText(name);});2.3 完整示例publicclassUserViewModelextendsViewModel{// 内部用 MutableLiveData可写privateMutableLiveDataUseruserLiveDatanewMutableLiveData();// 对外暴露 LiveData只读publicLiveDataUsergetUser(){returnuserLiveData;}publicvoidloadUser(){// 模拟异步请求newThread(()-{UseruserfetchFromNetwork();userLiveData.postValue(user);// 子线程用 postValue}).start();}publicvoidupdateName(Stringname){UseruseruserLiveData.getValue();if(user!null){user.setName(name);userLiveData.setValue(user);// 主线程用 setValue}}}publicclassMainActivityextendsAppCompatActivity{OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);UserViewModelviewModelnewViewModelProvider(this).get(UserViewModel.class);// 观察用户数据变化viewModel.getUser().observe(this,user-{TextViewtvNamefindViewById(R.id.tvName);tvName.setText(user.getName());});findViewById(R.id.btnLoad).setOnClickListener(v-{viewModel.loadUser();});}}三、LiveData 的类层次LiveDataT抽象类不可直接修改值 └── MutableLiveDataT公开 setValue/postValue └── MediatorLiveDataT可合并多个 LiveData3.1 MutableLiveData// 对外暴露时用 LiveData只读内部用 MutableLiveData可写privateMutableLiveDataUser_usernewMutableLiveData();publicLiveDataUsergetUser(){return_user;// 返回父类外部只能观察不能修改}为什么这样设计确保所有数据变更都经过 ViewModel 的业务方法避免外部随意修改导致状态混乱。3.2 MediatorLiveData合并多个数据源MediatorLiveDataStringresultnewMediatorLiveData();// 合并两个 LiveData任一变化都更新 resultresult.addSource(liveData1,value-result.setValue(value));result.addSource(liveData2,value-result.setValue(value));四、Transformations数据转换无需在 Activity 中处理转换逻辑直接在 LiveData 链上操作4.1 map —— 类型转换// 将 User 转换为 String用户名LiveDataStringuserNameTransformations.map(userLiveData,user-user.getName());4.2 switchMap —— 类似 RxJava 的 flatMap// userId 变化时自动重新请求对应的 UserLiveDataUseruserTransformations.switchMap(userIdLiveData,id-repository.getUser(id));map vs switchMap 的区别方法用途返回值map同步转换LiveDataY输入变化时直接转换switchMap异步依赖LiveDataY输入变化时返回新的 LiveData自动切换观察源五、内部原理简述┌─────────────────┐ observe() ┌─────────────────┐ │ Activity │ ──────────────────→ │ LiveData │ │ (LifecycleOwner)│ │ │ └────────┬────────┘ │ ┌───────────┐ │ │ │ │ mData │ │ ← 持有最新数据 生命周期变化 │ │ (T) │ │ │ │ └───────────┘ │ ▼ │ ┌───────────┐ │ ┌─────────┐ │ │ mObservers│ │ │RESUMED │ ──→ onActive() │ │ MapObserver│ │STARTED │ ──→ 分发数据 │ │ ,ObserverWrapper│ │CREATED │ │ └───────────┘ │ │DESTROYED│ ──→ 自动移除Observer └─────────────────┘ └─────────┘关键机制LifecycleBoundObserver内部实现了LifecycleEventObserver能感知LifecycleOwner的生命周期变化活跃状态判断只有LifecycleOwner处于STARTED或RESUMED时才分发数据自动清理当生命周期进入DESTROYED时自动调用removeObserver()版本号机制内部维护mVersion新 Observer 注册时如果版本落后会立即补发最新数据实现粘性特性六、LiveData vs 普通回调对比项普通接口回调LiveData内存泄漏风险高需手动 unregister无自动清理生命周期安全需手动判断 Activity 是否销毁自动感知只活跃时分发配置变更后数据丢失需手动保存配合 ViewModel 自动存活代码复杂度需要写注册/注销逻辑一行observe()搞定新观察者收不到历史数据立即收到最近一次数据线程安全需自行处理postValue()自动切主线程七、常见陷阱7.1postValue()连续调用会丢值// ❌ 错误只会保留最后一个值 CliveData.postValue(A);liveData.postValue(B);liveData.postValue(C);原因postValue()将值存入临时变量mPendingData然后 post 一个 Runnable 到主线程执行setValue()。如果主线程还没执行新的postValue()会覆盖旧值。解决需要连续更新时用setValue()确保在主线程或者合并为一次更新。7.2 粘性问题新 Observer 收到旧数据// 如果 userLiveData 已经有值这个 Observer 会立即触发userLiveData.observe(this,user-{// 可能不是你期望的新事件而是上次的旧数据// 例如旋转屏幕后重新注册会再次收到旧数据});解决方案使用SingleLiveEvent专门处理一次性事件如 Toast、导航、对话框。publicclassSingleLiveEventTextendsMutableLiveDataT{privatefinalAtomicBooleanmPendingnewAtomicBoolean(false);Overridepublicvoidobserve(LifecycleOwnerowner,Observer?superTobserver){super.observe(owner,t-{if(mPending.compareAndSet(true,false)){observer.onChanged(t);}});}OverridepublicvoidsetValue(Tt){mPending.set(true);super.setValue(t);}}7.3setValue()在子线程调用会崩溃newThread(()-{liveData.setValue(error);// ❌ IllegalStateException: Cannot invoke setValue on a background thread}).start();解决子线程用postValue()。7.4 在onCreate()中重复注册 ObserverOverridepublicvoidonCreate(BundlesavedInstanceState){// ❌ 错误每次 onCreate 都会新增一个 ObserverviewModel.getData().observe(this,data-{...});}解决将observe()放在onCreate()中是正确的配置变更后会重新创建 Activity但 ViewModel 存活Observer 会自动清理旧的但要避免在会多次调用的方法如onResume()中注册。八、常见问题Q1LiveData 为什么能避免内存泄漏LiveData 内部绑定了LifecycleOwner当 Activity/Fragment 进入DESTROYED状态时LifecycleBoundObserver会自动调用removeObserver()移除引用从而避免内存泄漏。开发者无需手动 unregister。Q2setValue()和postValue()有什么区别setValue()必须在主线程调用同步立即触发所有活跃 Observer 的onChanged()postValue()可在任意线程调用内部通过ArchTaskExecutor切到主线程执行setValue()。连续调用postValue()可能只保留最后一次的值因为mPendingData被覆盖Q3LiveData 的粘性特性是什么新注册的 Observer 会立即收到 LiveData 最近一次setValue()的数据。这是因为 LiveData 内部维护了版本号mVersion新 Observer 的版本号初始为-1注册时会判断如果 LiveData 版本更新则立即补发数据。Q4LiveData 配合 ViewModel 为什么能屏幕旋转存活ViewModel 生命周期比 Activity 长由ViewModelProvider管理配置变更时不会重新创建。LiveData 存在 ViewModel 中所以数据不会丢失。新的 Activity 创建后重新observe()仍能立即收到之前的数据。Q5LiveData 和 RxJava 的区别维度LiveDataRxJava生命周期感知✅ 原生支持❌ 需手动管理配合AutoDispose/RxLifecycle学习成本低高操作符众多功能丰富度简单观察 转换强大丰富的操作符链背压支持❌ 不支持✅Flowable支持线程切换仅主线程/子线程切主线程强大的调度器Schedulers.io()、AndroidSchedulers.mainThread()等适用场景Android UI 数据绑定复杂异步流、网络请求链式处理Q6LiveData 的observeForever()是什么observeForever(Observer)可以不绑定生命周期永久观察。但需要手动调用removeObserver()注销否则会造成内存泄漏。一般用于需要跨生命周期观察的场景如 Service 中。Q7为什么 LiveData 的getValue()可能返回 nullgetValue()返回的是 LiveData 当前持有的值。如果还没有调用过setValue()或postValue()或者值被显式设为 null就会返回 null。它不会触发观察只是同步读取当前值。九、总结LiveData 的本质是**“带生命周期感知的观察者模式”**。它让数据更新与 UI 刷新解耦开发者只需关注数据是什么不用关心什么时候更新 UI和会不会泄漏。核心使用口诀主线程更新用setValue()子线程更新用postValue()对外暴露用LiveData只读内部持有用MutableLiveData可写一次性事件用SingleLiveEvent数据转换用Transformations.map/switchMap
返回列表