Android Jetpack之LiveData源码分析

Posted 笨鸟-先飞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Jetpack之LiveData源码分析相关的知识,希望对你有一定的参考价值。

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("内容改变了");
            
        );
    



下面的源码分析中,有些情况会设计到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);
    

看到这里,其实发现很简单,添加观察者,其实,就是在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;
    


这里,我们可以看到,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);
    

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

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

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

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

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

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

UnPeek-LiveData 解决方案

以上是关于Android Jetpack之LiveData源码分析的主要内容,如果未能解决你的问题,请参考以下文章

Android kotlin 系列讲解(进阶篇)Jetpack系列之LiveData

Android JetPack组件之LiveData的使用详解

Android Jetpack之LiveData源码分析

Android Jetpack 技术内幕探索之 LiveData

Jetpack之LiveData扩展MediatorLiveData

jetpack之LiveData