Jetpack:LiveData使用指南,实现原理详细解析!

observeForever


无论页面处于什么状态,observeForever()都能收到通知。因此,在用完之后,一定要记得调用removeObserver()方法来移除观察者,否则会造成了内存泄漏。

ViewModel+LiveData实现Fragment间通信

==================================================================================================

原理


ViewModel时储存在ViewModelStore里面的,而ViewModelStore是通过getViewModelStore获取的,我们只需要传入activity的ViewModelStoreOwner接口,那么多个fragment之间就获取的是同一个ViewModelStore了,那这样就能获取到同一个ViewModel了,然后利用LiveData观察者的特性即可实现数据之间的共享了。

具体实现


1.定义ShareDataViewModel利用LiveData包装progress字段。

class ShareDataViewModel : ViewModel() {

val progress: MutableLiveData by lazy(LazyThreadSafetyMode.NONE) {

MutableLiveData(0)

}

}

2.定义相关布局文件,将两个fragment平放在一个布局里面。

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:orientation=“vertical”

android:layout_width=“match_parent”

android:layout_height=“match_parent”>

<FrameLayout

android:id=“@+id/fl_id_1”

android:layout_width=“match_parent”

android:layout_height=“0dp”

android:layout_weight=“1”/>

<View

android:layout_width=“match_parent”

android:layout_height=“1dp”

android:background=“@color/design_default_color_primary”/>

<FrameLayout

android:id=“@+id/fl_id_2”

android:layout_width=“match_parent”

android:layout_height=“0dp”

android:layout_weight=“1”/>

定义fragment布局文件

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:layout_width=“match_parent”

android:layout_height=“match_parent”>

<TextView

android:id=“@+id/tv_content”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_centerInParent=“true”

android:layout_above=“@id/seekbar”

android:text=“@string/app_name”/>

<SeekBar

android:id=“@+id/seekbar”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_marginTop=“20dp”

android:max=“100”

android:layout_centerInParent=“true”/>

3.编写Fragment代码,实现具体的通信,注意ViewModelProvider传入activity

class SeekBarFragment

@JvmOverloads

constructor(private val text: String = “”) : Fragment() {

override fun onCreateView(

inflater: LayoutInflater,

container: ViewGroup?,

savedInstanceState: Bundle?

): View {

return FragmentSeekbarBinding.inflate(layoutInflater).let {

fragmentSeekBarBinding ->

fragmentSeekBarBinding.tvContent.text = this.text

//注意这里使用activity,因为如果想共享数据需要使用同一个ViewModelStore。所以都是用activity的。

val liveDataProgress = ViewModelProvider(activity!!)[ShareDataViewModel::class.java].progress

//通过observe观察ViewModel中字段数据的变化,并在变化时得到通知

liveDataProgress.observe(this){

progress->

fragmentSeekBarBinding.seekbar.progress = progress

}

fragmentSeekBarBinding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {

override fun onProgressChanged(

seekBar: SeekBar?,

progress: Int,

fromUser: Boolean

) {

//当用户操作SeekBar时,更新ViewModel中的数据

liveDataProgress.value = progress

}

override fun onStartTrackingTouch(seekBar: SeekBar?) {

}

override fun onStopTrackingTouch(seekBar: SeekBar?) {

}

})

fragmentSeekBarBinding.root

}

}

}

5.编写activity代码,将fragment实例化,并放入activity中。

class ShareFragmentActivity : AppCompatActivity(){

lateinit var binding: ActivityFragmentContentBinding

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

initView()

}

private fun initView(){

binding = ActivityFragmentContentBinding.inflate(layoutInflater)

setContentView(binding.root)

supportFragmentManager.beginTransaction().add(binding.flId1.id,SeekBarFragment(“One-Fragment”)).commit()

supportFragmentManager.beginTransaction().add(binding.flId2.id,SeekBarFragment(“Two-Fragment”)).commit()

}

}

结果


无论滑动上面的SeekBar还是下面的SeekBar,另一个Fragment的SeekBar一定会跟着滑动。在滑动SeekBar时,通过LiveData.setValue()方法,修改了ViewModel中LiveData包装的数据(progress字段)。由于Fragment通过LiveData.observe()方法监听了数据的变化,因此progress字段被修改后,Fragment能够第一时间收到通知并更新UI。

在这里插入图片描述

LiveData原理详解

===============================================================================

LiveData.observe的源码:

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

}

上面说到过observe只能在主线程使用,observe里面第一步就用assertMainThread进行了主线程判断,如果当前运行的不是主线程的话,直接就抛异常了(assertMainThread内部实现在上面贴过了)。同理LiveData的observeForever、removeObserver、removeObservers与setValue,也是一样的道理,在方法的第一步就用assertMainThread进行了判断,只能在主线程使用,否则就抛异常

接下来看和生命周期相关的内容,如果当前生命周期是DESTROYED的话就直接return。LifecycleOwner传入到了LifecycleBoundObserver里面进行了包装,将包装后的对象和observer传入了mObservers(一个key value集合)进行保存,最后注册生命周期。所以看看LifecycleBoundObserver做了什么操作

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;

activeStateChanged(shouldBeActive());

currentState = mOwner.getLifecycle().getCurrentState();

}

}

@Override

boolean isAttachedTo(LifecycleOwner owner) {

return mOwner == owner;

}

@Override

void detachObserver() {

mOwner.getLifecycle().removeObserver(this);

}

}

先看onStateChanged方法(当生命周期变化的话会回调该方法),判断如果当前的生命周期是DESTROYED直接就移除了观察者接下来判断当前生命周期的状态是否应该激活当前的观察者(只有观察者被激活才能接收到数据的变化),调用了shouldBeActive,而shouldBeActive则是判断了当前的生命周期是否大于等于STARTED,简单推理那应该就是生命周期在大于等于STARTED时才是激活状态。允许接收到值得变化。所以使用observe可接受到值得生命周期得范围应该时大于等于STARTED小于DESTROY

接下来看activeStateChanged方法,我们假设此时生命周期大于STARTED,则传入得就是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);

}

}

}

赋值状态为激活状态,changeActiveCounter改变当前激活状态得数量(这里不进入方法内分析了,该方法主要记录了处于激活状态得observe数量,然后判断如果激活状态得数量由从0到1得话调用了onActive方法,激活状态数量由1到0得话调用了onInactive方法。这两方法都是空方法,需要我们自己手动取实现,比如继承MutableLiveData或者LiveData取自己实现一个LiveData,具体要不要实现取决于自己得业务逻辑)。接下来就是判断如果在激活状态的话,就调用dispatchingValue(传入了this)开始分发事件

void dispatchingValue(@Nullable ObserverWrapper initiator) {

if (mDispatchingValue) {

mDispatchInvalidated = true;

return;

}

mDispatchingValue = true;

do {

mDispatchInvalidated = false;

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;

}

因为传入了initiator,所以就调用了considerNotify

private void considerNotify(ObserverWrapper observer) {

if (!observer.mActive) {

return;

}

if (!observer.shouldBeActive()) {

observer.activeStateChanged(false);

return;

}

if (observer.mLastVersion >= mVersion) {

return;

}

observer.mLastVersion = mVersion;

//调用到了observer得onChanged方法

observer.mObserver.onChanged((T) mData);

}

这个就很简单明了,满足激活状态下,shouldBeActive就是之前分析得大于等于STARTED,最后就调用了mObserver.onChanged就调用到了我们传入得Observer,实现了值得分发

observeForever与observe得区别就是,observe使用得是LifecycleBoundObserver进行得包装,对生命周期进行了监控,而observeForever使用了AlwaysActiveObserver进行了包装

private class AlwaysActiveObserver extends ObserverWrapper {

AlwaysActiveObserver(Observer<? super T> observer) {

super(observer);

}

@Override

boolean shouldBeActive() {

return true;

}

}

里面没有对生命周期进行监控合适进行观察者移除销毁,且shouldBeActive永远返回true,所以无论页面处于什么状态,observeForever()都能收到通知。

再看看setValue得源码

protected void setValue(T value) {

assertMainThread(“setValue”);

mVersion++;

mData = value;

dispatchingValue(null);

}

其实也没干啥,判断主线程,调用版本记录,赋值,返回就调用到了dispatchingValue方法,dispatchingValue不就和我们前面分析得一样嘛,只不过传入了空,这时候,走了else得逻辑从集合里面去除所有得observe进行调度分发而已

看看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

setValue((T) newValue);

}

};

其实就是将异步线程调度到主线程执行,执行得mPostValueRunnable里面还是调用了setValue

其他杂谈

最后

在此为大家准备了四节优质的Android高级进阶视频:

架构师项目实战——全球首批Android开发者对Android架构的见解

附相关架构及资料

image.png

往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

private final Runnable mPostValueRunnable = new Runnable() {

@SuppressWarnings(“unchecked”)

@Override

public void run() {

Object newValue;

synchronized (mDataLock) {

newValue = mPendingData;

mPendingData = NOT_SET;

}

//调用了setValue

setValue((T) newValue);

}

};

其实就是将异步线程调度到主线程执行,执行得mPostValueRunnable里面还是调用了setValue

其他杂谈

最后

在此为大家准备了四节优质的Android高级进阶视频:

架构师项目实战——全球首批Android开发者对Android架构的见解

附相关架构及资料

[外链图片转存中…(img-gwraow7W-1715782436054)]

往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值