IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 的 MVVM 之 LiveData源码研究 -> 正文阅读

[移动开发]Android 的 MVVM 之 LiveData源码研究

????????Android? 官方提供的MVVM模式 ,有 DataBinding,ViewModel 和 LiveData组成。

??????? 废话少说,先看下LiveData怎么用的?

class TestActivity : AppCompatActivity() {

    private var data: MutableLiveData<String> = MutableLiveData()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)

        // 通过 observe LiveData 数据
        data.observe(this, object : Observer<String> {

            // 通过 observe 回调 数据
            override fun onChanged(t: String?) {
                Timber.tag("MyTest").d(t)
            }

        })
        
        button.setOnClickListener {
            /**
             * 通过 postValue / setValue 设置数据
             * setValue() 必须在主线程
             * postValue() 在哪个线程设置都可以 最终还是通过 setValue() 设置的
             * */ 
            data.postValue("postValue12345")
            data.setValue("setValue12345")
        }
    }
}

????????LiveData 是一个抽象类,不能创建实例,那就用它的子类? MutableLiveData 来创建一个LiveData。

????????很明显,这是一种观察者模式。LiveData 通过 observe() 注册监听数据,通过setValue / postValue 设置数据。其实postValue() 最终还是通过 setValue() 设置的。用过的朋友相信都知道。

????????但是这篇文章,不是看下怎么使用,是探究一下 LiveData 源码,看它是怎么做到和宿主生命周期绑定的。

????????好的,我们带着? 4? 个问题去看源码:

??????? 【问题1】:如何做到伴随宿主Activity 或Framgent 销毁而销毁,无需手动取消监?

??????? 【问题2】:如何做到只有在宿主Activity 或Framgent 可以见时,才把新数据发送给监听者的?

??????? 【问题3】:如何做到在宿主Activity 或Framgent 不可见时设置数据,不会立马把新数据发送给监听者,等Activity 或Framgent 重新可见时再把新数据发送给监听者?

??????? 【问题4】:如何做到在宿主Activity 或Framgent 重新可见时,只有在数据被重新更新了的情况下才去发送数据给观察者,数据没有被更新过不会通知监听者

-------------------Part1-----------------------

首先,我们看下注册监听时做了些什么逻辑,看下 LiveData.observe() 的源码

    

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer){
        // ---------------注释1 ---------------
        assertMainThread("observe");
        // ---------------注释2 ---------------
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }

        //  注释3 这个是重点 大部分逻辑在这个 LifecycleBoundObserver 里面
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

        // ---------------注释4 ---------------
        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;
        }

        // ---------------注释5 ---------------
        owner.getLifecycle().addObserver(wrapper);
    }

注释1】:检测确保是在主线程监听,否则会抛出异常,所以 LiveData 的监听必须在主线程,有兴趣的同学可以进去看一下,里面很简单的代码

注释2】: 如果当前宿主?LifecycleOwner ( 即 :Activity / Framgent) 已经是 destory 状态,那就没必要注册监听了,直接退出。这个逻辑无需解释了

注释3】: 通过 LifecycleBoundObserver 把 LifecycleOwner 和 LiveData 的监听者Observer 绑定在一起,让? LifecycleOwner? 的生命周期 和? LiveData 的监听者Observer联动起来,具体怎么联动法,等下再看。

注释4】: 把创建好的 LiveData 监听者保存在 mObservers里面。之后有数据变化时,会遍历 mObservers 的每个元素,把符合条件的监听者逐个发新数据。

注释5】:? LifecycleOwner 监听生命周期,其生命周期状态变化的回调都在? LifecycleBoundObserver 回调。

所以,这一部分总结一下,就是 LifecycleBoundObserver? 把? LifecycleOwner 和 LiveData 的监听者绑定联动起来,让监听者感知 Activity/Fragment的生命周期。

-------------------Part2-----------------------

我们就看上面所说道的?LifecycleBoundObserver 就可以了,看下这个 LifecycleBoundObserver? 是怎么实现的

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {

        //省略无关紧要的代码.....................

        @Override
        boolean shouldBeActive() {
            // 这里的意思是只有在LifecycleOwner(Activity / Fragment) 可见时才会返回 true
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        // ----------------注释1---------------
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            // ----------------注释2---------------
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            // ----------------注释3---------------
            activeStateChanged(shouldBeActive());
        }

        //省略无关紧要的代码.....................
    }



    private abstract class ObserverWrapper {

    	//省略无关紧要的代码.....................
       
        
        void activeStateChanged(boolean newActive) {
            // 状态和之前一样不执行,这个很合理
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                // 空实现,可以重写此方法自己执行自己的拓展业务逻辑
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                // 同样空实现,可以重写此方法自己执行自己的拓展业务逻辑
                onInactive();
            }
            if (mActive) {
                // ----------------注释4--------------- 
                dispatchingValue(this);
            }
        }
    }

省略了一些无关紧要的代码,就看到 LifecycleBoundObserver?? 是集成于? ObserverWrapper 以及 实现了? LifecycleEventObserver 接口 ,

注释1】: 宿主?LifecycleOwner ( 即 :Activity / Framgent) 生命周期的变化,会通过注释1这个 onStateChanged() 这个方法回调,这个就是【Part1】注释5? owner.getLifecycle().addObserver(wrapper) 的作用

注释2】:当宿主?LifecycleOwner ( 即 :Activity / Framgent)的生命周期是 destory 时,会把这个监听者移除掉,这个【Part1】注释4相对应,观察者模式的监听和取消。这个就是解释了我们的【问题1】(如何做到伴随宿主Activity 或Framgent 可以销毁而销毁。无需手动取消监的?)

注释3】:状态变化最终调用 activeStateChanged() ,这个方法在 LifecycleBoundObserver?? 父类? ObserverWrapper? 里面,这里面的逻辑看父类的代码就清楚了。但是这里传入了一个参数,参数通过 shouldBeActive() 获得,里面的逻辑有兴趣的同学可以自己进入看一下,就是只有在LifecycleOwner( 即 :Activity / Framgent) 可见时才会返回 true。

注释4】:最终 dispatchingValue() 去通知监听者,但是这里有个条件,就是这个方法的入参newActive是true时才会执行,很明显,这个 newActive 就是注释3传入的,也就是 LifecycleOwner( 即 :Activity / Framgent)可见时才会为true,才会执行?dispatchingValue()? 去通知监听者,这个就是 【问题2】和 【问题3】。不可见不通知,重新可见再通知。

好了,到这里就是我们就很容易引出一个问题,当我们的 Activity / Framgent 每次重新可见时,都通知观察者吗?按理应该在数据有个变化才通知,没有变化时没必要通知的。这就是我们的问题【问题4】了。其实都是在上面所说的 dispatchingValue()? 方法里

-------------------Part3-----------------------

好,我们看一下 dispatchingValue() 里面的逻辑

    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                //--------注释1 执行通知
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    //--------注释2 执行通知
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }



   private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        // ----- 注释3 当前 Version 是否已经发送过,发送过退出不需要发送
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        // ----- 注释4 保存当前 Version 表示当前数据已经发送给观察者了 
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

其实 dispatchingValue()? 就是遍历所有观察者,把数据把数据发送给观察者,主要看 【注释1】和 【注释2】即可,里面就是执行发送给观察者,但是这一步还是没看到我们【问题4】的答案。

我们再进入【注释1】和【注释2】进入的方法 considerNotify() 里面,可以看到【注释3】和 【注释4】,这就是判断当前数据是不是已经发送过了,至于? mVersion 是什么时候设置的,搜一下引用即可看到是在 LiveData.setValue() 的时候设置。因为postValue() 最终还是通过 setValue() 设置的,所通过哪种方式设置数据,都会跑进 LiveData.setValue()来。

    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

一目了然了吧,,,,,,,,,

所以【问题4】 整个流程是:每个 LiveDate?对应保存一个Version, LiveDate?每被设置一次数据,对应的 Version 会自增1,当这个数据被发送给观察者后,这个 Version 会被存起来,当Activity 从不可见回到可见时,它会判断存起来的 Version 和 LiveDate 的 Version 是不是一致,如果是一致就代表这个数据已经发送过给观察者了,不会再次多余的发送一次,只有在不一致时,才会发新的数据发送给观察者。这就是为什么 Activity / Fragment 就算多次从不可见回到可见时,都只会发送一次同样的数据给观察者。这就是我们所要找的【问题4】的答案了。

以上代码逻辑如有误,请留言指出,谢谢

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-24 10:40:21  更:2021-09-24 10:41:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:58:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码