LiveData介绍

1、简介

同时具有观察者身份和被观察者身份的组件、LiveData数据的改变,可以监听到其的变化。用数据驱动的思想替换了常规接口回调的方式。

2、使用

  • 简单的使用
    (1)创建一个LiveData
/**
 *   author : weishixiong
 *   e-mail : weishixiong@pudutech.com
 *   date   : 2022/2/22 10:48
 *   desc   :单例MyLiveData
 */
object MyLiveData {
    val data = MutableLiveData<String>()
}

(2)改变并监听其数据的变化

class MainActivity : AppCompatActivity() {
    val TAG = javaClass.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        MyLiveData.data.observe(this, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.e(TAG, "onChanged:${Thread.currentThread().name} and  ${t}")
            }

        })
        MyLiveData.data.postValue("hello world")

class MainActivity : AppCompatActivity() {
    val TAG = javaClass.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        MyLiveData.data.observe(this, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.e(TAG, "onChanged:${Thread.currentThread().name} and  ${t}")
            }
        })
        MyLiveData.data.value = "hello "
        thread {
            MyLiveData.data.postValue("world")
        }
    }
}
com.example.lifecycle E/MainActivity: onChanged:main and  hello 
com.example.lifecycle E/MainActivity: onChanged:main and  world
  • setValue和postValue的区别

(1)setValue只能在主线程调用
(2)postValue既能在主线程调用,也能在子线程调用,如果需要在子线程调用改变LiveData的数据,使用postValue
(3)postValue最终也是调用到setValue方法,通过Handler线程切换到主线程,然后在主线程调用setValue
如下源码体现:
调用postValue方法,在postValue方法中调用postToMainThread方法

    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

在postToMainThread方法中,拿到主线程的Looper设置给Handler,在调用 mMainHandler.post(runnable);

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

在Runnable中执行setValue方法

   private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    }
  • LiveData的粘性事件
    通常在使用LiveData的使用,我们都是先调用observe方法订阅,然后再改变数据。
    但是假如我们先改变数据,然后再订阅,其实也是能收到数据的变化,这种现象称之为粘性事件,这并不是一个BUG,而是LiveData的特性。
    例如:我们再MainActivity1中先对LiveData的值进行改变,然后再跳转到MainActivity2订阅LiveData,来看看现象
        MyLiveData.data.value = "hello world"
        findViewById<TextView>(R.id.tv_click).setOnClickListener {
            startActivity(Intent(this, Main2Activity::class.java))
        }
class Main2Activity : AppCompatActivity() {
    val TAG = javaClass.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        MyLiveData.data.observe(this, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.e(TAG, "onChanged:${Thread.currentThread().name} and  ${t}")
            }
        })
    }
}
Main2Activity: onChanged:main and  hello world

我们看到在Main2Activity 依然能收到LiveData变化之后的数据。在后面源码分析我们将分析为什么?

3、源码简单分析

  • LiveData的注册
    调用LiveData的observe进行注册,并传入当前Activity的实例this,和Observe的实现类,重写onChanged函数
  MyLiveData.data.observe(this, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.e(TAG, "onChanged:${Thread.currentThread().name} and  ${t}")
            }
        })

在observe方法中,首先将我们的宿主和observer包装成一个LifecycleBoundObserver,而LifecycleBoundObserver实现了LifecycleEventObserver接口并继承了ObserverWrapper类,这样一来LifecycleBoundObserver就可以监听宿主Activity的生命周期并持有了observer对象。

@MainThread
   public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
       assertMainThread("observe");
       if (owner.getLifecycle().getCurrentState() == DESTROYED) {
           return;
       }
     //创建LifecycleBoundObserver  监听宿主的生命周期,并持有observer对象
       LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
   //同时将LifecycleBoundObserver存入到一个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;
       }
       owner.getLifecycle().addObserver(wrapper);
   }

同时调用了putIfAbsent 将LifecycleBoundObserver 对象存到一个map中。然后调用addObserver,将LifecycleBoundObserver 关联到宿主Activity中,监听其生命周期。
以上代码小结:LiveData调用observe方法注册的时候,主要做了两个工作
(1)创建一个LifecycleBoundObserver对象,并持有observer。监听宿主Activity的生命周期
(2)将LifecycleBoundObserver存到一个map中

  • 设置LiveData的数据
    通过使用setValue和postValue方法设置LiveData的数据,最终都会调用到setValue这话方法,
@MainThread
  protected void setValue(T value) {
      assertMainThread("setValue");
      mVersion++;
      mData = value;
      dispatchingValue(null);
  }

在setValue方法中对mVersion成员变量+1,这个变量很关键,通过这个变量来判断LiveData数据是否改变了。然后再setValue方法中调用dispatchingValue方法,意思就是将改变之后的数据分发出去。dispatchingValue方法如下:

  void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                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;
    }

由于dispatchingValue方法传的参数为null,所有会走到else中去,接着遍历之前存到map中的LifecycleBoundObserver对象,调用considerNotify函数

@SuppressWarnings("unchecked")
    private void considerNotify(ObserverWrapper observer) {
    //判断是否可见
        if (!observer.mActive) {
            return;
        }
    //判断是否可见
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

然后回调observer中的onChanged方法。而在调用onChanged方法之前主要做了两个判断:
(1)通过LifecycleBoundObserver监听Activity的生命周期,调用shouldBeActive函数和mActive属性,判断Activity是否可见,如果不可见直接return,所以当我们的Activity是不可见的时候,是监听不到数据的变化的。
如果需要不可见的时候也监听数据的变化可以采用observeForever
(2)判断LifecycleBoundObserver中持有的版本mLastVersion 是否小于LiveData的版本,如果小于,所以mVersion有做过++,因为我们在setValue的时候,有对mVersion+1操作。
在初始化的时候mVersion和mLastVersion的版本都为-1。当mVersion+1之后,mVersion版本>LifecycleBoundObserver中mLastVersion 的版本。说明有数据改变,所以直接回调onChanged函数。接着对齐版本,将mVersion的值,赋值给mLastVersion。
在上面我们可以看到主要通过dispatchingValue这个函数,将数据分发出去,然后回调我们的onChanged函数
那为什么数据会粘性呢?
我们来观察调用dispatchingValue的地方,除了LiveData设置数据的时候主动触发,同时在Activity生命周期变化的时候,也会触发。我们来看下代码

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
     @NonNull
     final LifecycleOwner mOwner;

     LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
         super(observer);
         mOwner = owner;
     }
     @Override
     boolean shouldBeActive() {
         return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
     }
     @Override
     public void onStateChanged(@NonNull LifecycleOwner source,
             @NonNull Lifecycle.Event event) {
         Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
         if (currentState == DESTROYED) {
             removeObserver(mObserver);
             return;
         }
         Lifecycle.State prevState = null;
         while (prevState != currentState) {
             prevState = currentState;
             activeStateChanged(shouldBeActive());
             currentState = mOwner.getLifecycle().getCurrentState();
         }
     }
     @Override
     boolean isAttachedTo(LifecycleOwner owner) {
         return mOwner == owner;
     }
     @Override
     void detachObserver() {
         mOwner.getLifecycle().removeObserver(this);
     }
 }
 private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

        ObserverWrapper(Observer<? super T> observer) {
            mObserver = observer;
        }

        abstract boolean shouldBeActive();

        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }

        void detachObserver() {
        }

        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
  
            mActive = newActive;
            changeActiveCounter(mActive ? 1 : -1);
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }

我们看到LifecycleBoundObserver 通过onStateChanged函数监听宿主Activity的生命周期,然后调用ObserverWrapper 中的activeStateChanged方法,在activeStateChanged方法中调用dispatchingValue分发数据。此时dispatchingValue方法的传参,传了this。也就是LifecycleBoundObserver 对象。

void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                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;
    }

这样就触发dispatchingValue方法中的if部分,调用 considerNotify(initiator);在considerNotify中的操作就一样了,同样是先判断版本,如果当前版本大于LifecycleBoundObserver 中的版本,就回调onChanged函数。
而由于在调用MainActivity1中调用setValue的时候,我们将mVersion++,所以mVersion的版本是>mLastVersion的。所以就会回调onChanged,MainActivity2就能收到LiveData数据的变化,这样就被称为了粘性事件。

private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }
  • 通过一张图大概分析LiveData的工作原理
image.png

总结

  • LiveData不管是通过post还是set,最终都是通过setValue改变数据
  • LiveData监听数据的变化主要通过当前版本mVersion和LifecycleBoundObserver 持有的版本进行比较。
  • LiveData持有了一个LifecycleBoundObserver 对象,主要是用于监听Activity的生命周期,持有一个observer作为观察者,观察LiveData的数据变化。变化的时候通过observer的onChanged函数
  • 触发onChanged方法,也就是监听到数据变化的时候,主要有两个途径
    (1)当调用LiveData的setValue方法的时候mVersion+1,然后主动去回调observer的onChanged方法,回调该方法之前判断版本和Activity是否可见,都满足的时候才调用。如果不满足,直接rerurn,不做处理。
    (2)当LifecycleBoundObserver 监听到Activity生命周期为可见的时候,同样按照上述步骤1判断版本号,决定是否回调onChanged方法。这也是粘性数据的根本原因,如果启动第二个Activity的时候,发现版本大于LifecycleBoundObserver 持有的版本,则说明数据有变化。回调onChanged方法
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容