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 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> LiveData原理解析 -> 正文阅读

[移动开发]LiveData原理解析

什么是LiveData

LiveDataAndroid Architecture Components 其中的一个组件。主要用于更新UI数据和组件之间传值。

1、LiveData是一种持有可被观察数据的类。它通过观察者模式实现了数据变化的动态通知,即当观察者生命周期处于活跃状态时,能够感知数据的变化。

2、能够感知生命周期,内部通过Lifecycle来感知生命周期,在Activity、Fragment、Service中当对应生命周期为Destroy的时候,会销毁观察者,避免内存泄露;

LiveData的简单使用

LiveData的使用十分方便,只需要简单的三步:

1、创建LiveData对象,LiveData是抽象类,所以需要创建它的子类MutableLiveData

2、设置观察者observe,第一个参数是LifecycleOwner对象,第二个是观察者监听,当数据改变的时候会在onChanged方法内做出响应;

3、设置数据,通过postValue或者setValue方法来更新数据;

public class MainActivity extends AppCompatActivity {
    private MutableLiveData liveData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 1.创建LiveData对象 
        liveData = new MutableLiveData();
        // 2.添加观察者
        liveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                // 提示数据变化
                Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show();
            }
        });
        findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 3.改变数据
                liveData.postValue("测试");
            }
        });
    }

}

LiveData原理

一、LiveData是如何实现观察者订阅,并发送事件的?

LiveData通过observe和observeForever来订阅观察者,查看源码可以看到

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    ///1、判断当前状态是否是DESTROYED,如果不是则添加观察者
    if (owner.getLifecycle().getCurrentState() != State.DESTROYED) {
        ///2、创建LifecycleBoundObserver类
        LiveData<T>.LifecycleBoundObserver wrapper = new LiveData.LifecycleBoundObserver(owner, observer);
        ///3、将观察者和LifecycleOwner添加到map中一一对应
        LiveData<T>.ObserverWrapper existing = (LiveData.ObserverWrapper)this.mObservers.putIfAbsent(observer, wrapper);
        // 对应观察者只能与一个owner绑定
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
        } else if (existing == null) {
            // 当不存在的时候添加LifecycleObserver
            owner.getLifecycle().addObserver(wrapper);
        }
    }
}

1、源码首先判断当前状态是否是DESTROYED,如果不是则不会注册当前;

2、创建LifecycleBoundObserver类,该类实现了生命周期与观察者的绑定,在此类中有个onStateChanged方法如下,onStateChanged方法中会在生命周期状态发生改变时判断当前状态是否是DESTROYED,如果是就移除当前监听者,避免内存泄露。

public void onStateChanged(LifecycleOwner source, Event event) {
    // 当生命周期处于DESTROYED的时候移除当前订阅者
    if (this.mOwner.getLifecycle().getCurrentState() == State.DESTROYED) {
        LiveData.this.removeObserver(this.mObserver);
    } else {
        // 非DESTROYED的时候进行状态改变
        this.activeStateChanged(this.shouldBeActive());
    }
}

LifecycleBoundObserver类继承ObserverWrapper类,ObserverWrapper又是观察者的包装类。

LifecycleBoundObserver类通过实现了GenericLifecycleObserver接口->LifecycleEventObserver接口,最终实现了LifecycleEventObserver接口,所以下面将wrapper添加到Lifecycle的监听中。

owner.getLifecycle().addObserver(wrapper);

3、LiveData中创建了一个Map来存储每一个观察者和生命周期的包装类,并且会判断当前对应观察者只能与一个owner绑定。

二、postValue和setValue过程分析

LiveData可以通过postValue和setValue来设置数据,当请求完网络数据的时候,就可以调用postValue或setValue来设置数据,当然postValue是可以在任意线程进行调用,setValue只能在主线程调用。postValue最终也是调用setValue方法。

下面分析一下postValue的源码执行过程:

MutableLiveData类中的postValue和setValue都是调用了父类(LiveData)的方法。直接查看LiveData的postValue方法:

protected void postValue(T value) {
    boolean postTask;
    synchronized(this.mDataLock) {
        postTask = this.mPendingData == NOT_SET;
        this.mPendingData = value;
    }

    if (postTask) {
        // 转到主线程去执行,所以postValue方法可以在任意线程执行
        ArchTaskExecutor.getInstance().postToMainThread(this.mPostValueRunnable);
    }
}

源码中最终会转到主线程去执行,所以postValue方法可以在任意线程执行,再查看mPostValueRunnable源码:

public LiveData() {
    this.mData = NOT_SET;
    this.mPendingData = NOT_SET;
    this.mVersion = -1;
    this.mPostValueRunnable = new Runnable() {
        public void run() {
            Object newValue;
            synchronized(LiveData.this.mDataLock) {
                newValue = LiveData.this.mPendingData;
                LiveData.this.mPendingData = LiveData.NOT_SET;
            }
			// 这里最终调用了setValue方法
            LiveData.this.setValue(newValue);
        }
    };
}

在LiveData的构造方法中创建了mPostValueRunnable,并在最后调用了setValue方法。下面再看一下setValue方法:

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    // 版本+1
    ++this.mVersion;
    // 将值赋值给全局变量mData
    this.mData = value;
    // 分发数据
    this.dispatchingValue((LiveData.ObserverWrapper)null);
}

setValue中主要做了三个事:

1、版本+1,LiveData的mVersion变量表示的是发送数据的版本,每次发送一次数据, 它都会+1;

2、将值赋值给全局变量mData;

3、调用dispatchingValue方法分发数据,dispatchingValue方法中主要调用的是considerNotify方法

private void considerNotify(LiveData<T>.ObserverWrapper observer) {
    // 如果观察者处于活跃状态
    if (observer.mActive) {
        // 判断是否应该改变状态
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
        } else if (observer.mLastVersion < this.mVersion) {// 当观察者的最后版本小于当前版本,表示有数据改变了
            // 将当前版本跟观察者的版本进行统一
            observer.mLastVersion = this.mVersion;
            // 触发onChange方法
            observer.mObserver.onChanged(this.mData);
        }
    }
}

查看shouldBeActive方法,这里通过LifeCycle的当前状态对比State.STARTED来判断,当是STARTED或者RESUMED状态时,才会触发observer的activeStateChanged方法,这时就会执行LifecycleBoundObserver中的activeStateChanged方法。

boolean shouldBeActive() {
    return this.mOwner.getLifecycle().getCurrentState().isAtLeast(State.STARTED);
}

另外,当observer的mLastVersion(初始值为-1)版本小于LiveData的mVersion时,就表示有新数据改变了,所以就会触发onChanged方法。

三、observe和observeForever区别

observer会自动监听生命周期,当是STARTED和RESUMED的时候才会触发订阅,而observeForever则是会一直检测数据变化,只要数据变化了就会触发订阅。

@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
    assertMainThread("observeForever");
    // 会创建一个总是活动的观察者
    LiveData<T>.AlwaysActiveObserver wrapper = new LiveData.AlwaysActiveObserver(observer);
	......
}

如源码所示,observeForever会创建一个总是活动的观察者AlwaysActiveObserver,改类继承ObserverWrapper,并实现了shouldBeActive方法,而且始终返回true,所以只要数据一改变,会触发onChanged方法。

private class AlwaysActiveObserver extends LiveData<T>.ObserverWrapper {
    AlwaysActiveObserver(Observer<? super T> observer) {
        super(observer);
    }
	// 一直返回true
    boolean shouldBeActive() {
        return true;
    }
}

而在LifecycleBoundObserver中实现了onStateChanged方法,在该方法中会根据当前状态是否为State.DESTROYED来自动移除监听者,所以observeForever则不会,所以需要在onDestroy中手动移除。

@Override
protected void onDestroy() {
    super.onDestroy();
    // 使用observeForever需要手动移除
    liveData.removeObserver(MyObserver);
}

四、LiveData粘性事件和数据倒灌

粘性事件:先setValue/postValue,后调用observe(),如果成功收到了回调,即为粘性事件。

数据倒灌:先setValue/postValue,后调用observe(new Obs()),至此收到了回调。然后再第二次调用observe(new anotherObs()),如果还能收到第一次的回调,则为“数据倒灌”。

大家可以看一下这篇文章:

关于LiveData粘性事件所带来问题的解决方案

组件之间传值工具类:

UnPeek-LiveData

LiveDataBus

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-11-22 12:27:21  更:2021-11-22 12:28:36 
 
开发: 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/24 5:24:51-

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