• 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 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() {
                @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("内容改变了");
                }
            });
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

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

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

    一、设置observe()方法

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

    下面看下源码

    
        private SafeIterableMap, ObserverWrapper> mObservers =
                new SafeIterableMap<>();
    		...
    	@MainThread
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer 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);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

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

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

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

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

    public class MutableLiveData extends LiveData {
    
        @Override
        public void setValue(T value) {
            super.setValue(value);
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

        @MainThread
        protected void setValue(T value) {
            assertMainThread("setValue");
    		//这里的版本,后面会说
            mVersion++;
            mData = value;
            dispatchingValue(null);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这里做了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, ObserverWrapper>> iterator =
                            mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                        considerNotify(iterator.next().getValue());
                        if (mDispatchInvalidated) {
                            break;
                        }
                    }
                }
            } while (mDispatchInvalidated);
            mDispatchingValue = false;
        }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    这里,我们可以看到,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);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

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

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

    在这里插入图片描述

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

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

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

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

    UnPeek-LiveData 解决方案

  • 相关阅读:
    ElementPlus el-switch开关页面初始化时,change事件自动触发
    【SpringBoot】常用的的各种注解(二):Controller层相关注解
    接雨水问题
    C# 串口接收1次数据会进入2次串口接收事件serialPort1_DataReceived,第2次进入时串口缓冲区为空
    50行Python代码白嫖Github Actions, 每天检测收录优质项目的存活状态(提供csv纯净数据下载)
    Neo4j入门基础:CREATE,DELETE,SET,REMOVE(看不懂我直接吃...)
    Nginx监控与告警:确保服务稳定运行
    R语言用逻辑回归、决策树和随机森林对信贷数据集进行分类预测
    qml入门教程:qml的初步使用
    使用互相关进行音频对齐
  • 原文地址:https://blog.csdn.net/ecliujianbo/article/details/128012255