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 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Jetpack--LiveData的使用和源码分析 -> 正文阅读

[移动开发]Jetpack--LiveData的使用和源码分析

Google官方解释:

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

说白了LiveData可以监听数据改变,从而进行操作。

先看三种场景:

1.通常情况--基本用法

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val textview:TextView = findViewById(R.id.tv)

        //写法1:采用lamda表达式
        MyLiveData.info.observe(this,{
            textview.text = it
        })
        //写法2:采用常规写法 传LifeCycleOwner 和new一个Observer并重写onChange方法
//        MyLiveData.info.observe(this,object: Observer<String>{
//            override fun onChanged(t: String?) {
//
//            }
//        })

        MyLiveData.info.value = "vivid-momo 1rd"  //主线程使用setValue
        //在KT中就等价与setValue

        thread{
            Thread.sleep(3000)
            MyLiveData.info.postValue("vivid-momo 2nd") //异步线程使用postValue
        }
        thread{
            Thread.sleep(6000)
            MyLiveData.info.postValue("vivid-momo 3rd") //异步线程使用postValue
        }

    }
}
//单例类+懒加载
object MyLiveData {

    val info:MutableLiveData<String> by lazy {  MutableLiveData() }
}

结果:启动后界面中的TextView默认显示"vivid-momo 1rd"后显示2nd最后显示3rd

?2.数据变化界面什么时候刷新

//LiveData UI 更新时机
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)

        val  but:Button = findViewById(R.id.but)

        but.setOnClickListener{
            startService(Intent(this,MyService::class.java))
            Toast.makeText(this, "启动Service", Toast.LENGTH_SHORT).show()
        }

        MyLiveData.info.observe(this, {
            Log.d("vivid-momo", "onCreate: 接受数据....")
            Toast.makeText(this, "接受到的数据是: ${it}", Toast.LENGTH_SHORT).show()
        })
    }
}
object MyLiveData {
    val info:MutableLiveData<String> by lazy {  MutableLiveData() }
}
class MyService : Service() {

    val TAG = "vivid-momo"
    override fun onBind(intent: Intent): IBinder ? = null
    
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        thread {
            for (x  in 1..10000){
                Log.d(TAG, "onStartCommand: 消息发送开始....${x}")
                MyLiveData.info.postValue("消息列表 -- ${x}")
                Thread.sleep(5000)
            }
        }
        return super.onStartCommand(intent, flags, startId)
    }
}

MainActivity: but用于启动Service 并且启动对MyLiveData中info观察

Service:隔5S修改一次数据

结果:

2022-04-25 01:09:14.962 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....1
2022-04-25 01:09:15.042 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
2022-04-25 01:09:19.963 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....2
2022-04-25 01:09:19.964 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
2022-04-25 01:09:24.964 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....3
2022-04-25 01:09:24.966 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
2022-04-25 01:09:29.965 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....4
2022-04-25 01:09:34.968 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....5
2022-04-25 01:09:39.970 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....6
2022-04-25 01:09:41.330 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
2022-04-25 01:09:44.971 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....7
2022-04-25 01:09:44.973 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
2022-04-25 01:09:49.973 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....8
2022-04-25 01:09:49.975 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
2022-04-25 01:09:54.974 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....9
2022-04-25 01:09:54.975 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....

原因:发送数据456是,退出了APK,所以不接受数据,故此UI不刷新

3:特殊情况下LiveData如何处理

先修改数据后启动数据观察

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main3)
        val  but:Button = findViewById(R.id.but)
        
        but.setOnClickListener {
            MyLiveData.info.value ="vivid-momo  先改变数据"
            startActivity(Intent(this,StartObserver::class.java))
        }
        
    }
}
object MyLiveData {
    val info:MutableLiveData<String> by lazy {  MutableLiveData() }
}
class StartObserver : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main4)

        MyLiveData.info.observe(this, {
            Log.d("vivid-momo", "onCreate: 接受到的数据是:${it}")
            Toast.makeText(this, "接受到的数据是:${it} ", Toast.LENGTH_SHORT).show()
        })
    }
}

结果:

2022-04-25 01:14:00.172 28144-28144/com.example.livedatademo D/vivid-momo: onCreate: 接受到的数据是:vivid-momo  先改变数据

先修改了数据在启动观察,仍然接受到了启动观察前的数据!!!

问题1:setValue和postValue到底有什么区别?

问题2:LiveData刷新数据有什么限制?

问题3:为什么先修改数据后启动监听,仍可以接受到启动监听前的数据?

回答这三个问题之前,我们先看看MyLiveData.info.observe(this,{ })中observe做了什么操作?

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
    // ignore
    return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
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;
}
    owner.getLifecycle().addObserver(wrapper);//结合LifeCycle
}

第一个参数:this 指当前MainActivity的环境变量,由于MainActivity继承了ComponentActivity,而ComponentActivity实现了LifecycleOwner 所以this 中就存在了LifecycleOwner。

第二个参数:new了一个Observer

observe中将this和Observer通过LifecycleBoundObserver重新实例化成wrapper?

LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
 }

LifecycleBoundObserver实例的时候会把MainActivity的环境(this)传给父类ObserverWrapper

this(LifecycleOwner)传给ObserverWrapper 能干什么?下面两个是关键方法

 @Override
 boolean shouldBeActive() {  
        //通过拿到的LifecycleOwner判断当前的MainActivity是否是活动状态
        //STARTED/RESUMED
      return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
 }

 @Override
 public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
      if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
           removeObserver(mObserver);
           return;
      }
       //如果MainActivity是STARTED/RESUMED状态执行
      activeStateChanged(shouldBeActive());
 }
        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            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) {
                dispatchingValue(this);//newActive 为true执行 
            }
        }
void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) { //initiator 为true,不为空
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
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;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData); //回调执行onChanage方法
    }

mDate是什么东西?

此时我们就要回答 问题1:setValue和postValue到底有什么区别?

//LiveData.java
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

当你执行setValue的时候,把你要设置的数据赋值给了mDate,所以onChanage方法中就可以获取到你设置的值(其实就是"vivid-momo 1rd"字符串)。

再看postValue是如何执行?

//LiveData.java    
protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        //执行子主线程切换
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
 }
private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            setValue((T) newValue);
        }
 };

postVlaue中将我们要改变得字符串赋值给了mPendingData ,而在mPostValueRunnable 中又将mPendingData赋值给了newValue。

但是mPostValueRunnable中还是用setValue去设置数据的,而setValue执行用于主线程,所以说一定使用了子线程切换为主线程执行。

子线程切换为主线程

    //DefaultTaskExecutor.java
    @Override
    public void postToMainThread(Runnable runnable) {
        if (mMainHandler == null) {
            synchronized (mLock) {
                if (mMainHandler == null) {
                    mMainHandler = new Handler(Looper.getMainLooper());
                }
            }
        }
        //noinspection ConstantConditions
        mMainHandler.post(runnable);
    }

问题2:LiveData刷新数据有什么限制?

通过上面ObserverWrapper中的activeStateChanged方法分析只有但MainActivity处于STARTED/RESUMED状态数据才会被分发,这也就解释了为什么当我们退出apk是接受不到MyService.java 中 postValue修改的值。

问题3:为什么先修改数据后启动监听,仍可以接受到启动监听前的数据?

先修改数据,后启动监听,此时监听可以收到之前修改的数据此时收到的数据成为粘性数据。

为什么后启动监听能收到之前的数据?如果需要去掉粘性如何操作?

一切的一切还要下面这段代码开始解释:

private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }

收到了数据那就说明observer.mObserver.onChanged((T) mData);肯定是执行了的

也就是说前面的三个判断没有命中执行return

第一个:当我们通过点击事件跳转到启动StartObserver.java中,之前在activeStateChanged方法中mActive赋值只有当观察者处于STARTED/RESUMED状态mActive为true,否则为false,当我们第一次进入StartObserver.java中此时mActive为true所以第一个判断不命中

第二个:当观察者(StartObserver.java)处于非活动状态,需要通过activeStateChanged更新mActive的值,当StartObserver.java可见时第二个判断也不会命中

第三个:当观察者(StartObserver.java)第一次启动的时候mVersion 的值为-1;

但是当执行setValue的时候对mVersion 进行了累加操作,此时mVersion 值为0;


    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++; //执行的累加
        mData = value;
        dispatchingValue(null);
    }
public abstract class LiveData<T> {

    static final int START_VERSION = -1;
    ......
    private int mVersion = START_VERSION;
    ......
}
private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;
        ......
}

而mLastVersion 初始值为-1;所以第三个判断也不会命中,所以数据会分发下去,但是如果我们先不执行setValue/postValue,mVersion就会和mLastVersion相等都为-1,就不会分发数据,也就是说如果我们不想要之前设置的数据,可以通过第三个判断来去除。

具体方法:设置数据后通过反射重新给mVersion赋值为-1.此时再去启动监听就不会收到之前设置的数据,也就是去除了粘性数据。

特别注意:

在不去除粘性的情况下,在启动观察前多次修改数据,只有最后一次的数据会被观察者接收到。

也就是说StartObserver中执行接收到"vivid-momo ?先改变数据4"这一条数据

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main3)
        val  but:Button = findViewById(R.id.but)

        but.setOnClickListener {
            MyLiveData.info.value ="vivid-momo  先改变数据0"
            MyLiveData.info.value ="vivid-momo  先改变数据1"
            MyLiveData.info.value ="vivid-momo  先改变数据2"
            MyLiveData.info.value ="vivid-momo  先改变数据3"
            MyLiveData.info.value ="vivid-momo  先改变数据4"
            startActivity(Intent(this,StartObserver::class.java))
        }
    }
}

总结:LiveData是结合LifeCycle的五个状态实现对数据的有效监听和刷新。

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

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