1

Android Jetpack之LiveData源码分析

 1 year ago
source link: https://blog.csdn.net/android_jianbo/article/details/128012255
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Android Jetpack之LiveData源码分析_笨鸟-先飞的博客-CSDN博客

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 activity、fragment 或 service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

如果观察者(由 Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。

您可以注册与实现 LifecycleOwner 接口的对象配对的观察者。有了这种关系,当相应的 Lifecycle 对象的状态变为 DESTROYED 时,便可移除此观察者。这对于 activity 和 fragment 特别有用,因为它们可以放心地观察 LiveData 对象,而不必担心泄露(当 activity 和 fragment 的生命周期被销毁时,系统会立即退订它们)。

LiveData 的优势:

  • 确保界面符合数据状态
  • 不会发生内存泄漏
  • 不会因 Activity停止而导致崩溃
  • 不再需要手动处理生命周期
  • 数据始终保持最新状态
  • 适当的配置更改
  • 共享资源

以上内容均来自官网,官网地址

在这里插入图片描述
通过之前的博客:LiveData的简单使用。我们了解了LiveData的基本使用。这里回顾一下

LiveData的简单实用(一般都是跟ViewModel一起实用)


public class LiveDataActivity extends AppCompatActivity {
    private TextView mTextContent;
    //使用LiveData
    private MutableLiveData<String> contentLiveData = new MutableLiveData<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_livedata_test);
        mTextContent = findViewById(R.id.tv_content);
        //设置 观察者
        contentLiveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                mTextContent.setText(s);
            }
        });
        //点击按钮,改变内容
        findViewById(R.id.btn_livedata_change).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                contentLiveData.setValue("内容改变了");
            }
        });
    }
}


newCodeMoreWhite.png

下面的源码分析中,有些情况会设计到Lifecycle()监控生命周期。有兴趣的可以看下:Android Jetpack之Lifecycle的使用及源码分析

下面,我们通过上面使用的步骤,来分析。LiveData内容都做了什么操作

一、设置observe()方法

添加观察者,并且我们无需关系,移除及内存泄露问题

下面看下源码


    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();
		...
	@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");

		//owner是Activity已经实现的(Lifecycle文章有说)
		//如果owner的生命周期已经结束的话,直接返回。避免了内存泄露,甚至Crash
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
		//wrapper包装类。里面主要是一些生命周期及版本的判断
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

		//这里,我们看到添加观察者的时候。是把观察者做key,放到了一个Map里面
        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;
        }
		//这里跟我们添加Lifecycle()一样,可以让wrapper监听owner生命周期,做一些判断
        owner.getLifecycle().addObserver(wrapper);
    }

newCodeMoreWhite.png

看到这里,其实发现很简单,添加观察者,其实,就是在LiveData里面创建了一个Map,把观察者存进去。

Map的值是个包含了owner(这里就是Activity,方便理解)和观察者observer的封装类。

二、分析通过set/postValue()改变内容

下面,我们看看LiveData的setValue()方法,是怎么把值传递过去的

public class MutableLiveData<T> extends LiveData<T> {

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}


这里调用了super.setValue()继续看

    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
		//这里的版本,后面会说
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

这里做了2个事情:

1,把值赋值给mData
2,调用 dispatchingValue(null);

我们接着看下

  void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
			//initiator这里通过上面知道,传递的是null。所以,走else
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
				//把所有观察者的Map,通过迭代器遍历
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }


newCodeMoreWhite.png

这里,我们可以看到,dispatchingValue()方法就是,遍历观察者所在的Map,然后,调用considerNotify()方法。

看下considerNotify()方法

 private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
		//通过上面一系列的判断,最终调用了观察者的onChanged方法。
        observer.mObserver.onChanged((T) mData);
    }
newCodeMoreWhite.png

这里,我们可以看到通过一些列生命周期的判断,版本的判断,最终调用了观察者的onChange()方法。
到这里,我们就已经走通了,所有的调用流程。

postValue的全过程跟setValue类似。只不过是后面通过Handler切换到了主线程上

在这里插入图片描述

[未完成]
上面有一点东西,我们没有说,那就是观察者observer的mLastVersion跟数据的mVersion问题。这个也是造成粘性数据的原因。但是,它跟EventBus不同的是,EventBus是提供了粘性数据的开关,但是,它并没有。

问题:LiveData的数据倒灌/粘性数据问题。

场景:(列表–详情(修改数据)–返回并点击其它列表–再次进入详情)(使用ShareViewModel)

SingleLiveEvent(解决一次事件,只消费一次),当注册多个观察者后,只有一个会受到,非常容易出错。

UnPeek-LiveData 解决方案


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK