• Jetpack系列 -- LiveData源码原理解析(解决黏性问题)


    一、LiveData是什么?

    注意:一般情况下,LiveData要配合ViewModel一起使用的,但是今天是单独使用LiveData,作为学习的话,我们可以只关注LiveData了。

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

    二、各种LiveData各种系列使用

    1.使用方式一:

    MyLiveData.kt 

    1. object MyLiveData {
    2. // 这里为info1的MutableLiveData 懒加载初始化(懒加载:用到时才加载)
    3. val info1 : MutableLiveData by lazy { MutableLiveData() }
    4. init {
    5. info1.value = "default"
    6. }
    7. }

    MainActivity.kt

    1. class MainActivity : AppCompatActivity() {
    2. override fun onCreate(savedInstanceState: Bundle?) {
    3. super.onCreate(savedInstanceState)
    4. setContentView(R.layout.activity_main)
    5. val textView: TextView = findViewById(R.id.tv_textview)
    6. activity_main.xml
    7. // 1.观察者 眼睛 环节
    8. MyLiveData.info1.observe(this, {
    9. textView.text = it
    10. })
    11. // 2.触发数据 环节
    12. MyLiveData.info1.value = "default"
    13. thread {
    14. Thread.sleep(3000)
    15. MyLiveData.info1.postValue("三秒钟后,修改了哦")
    16. }
    17. thread {
    18. Thread.sleep(6000)
    19. MyLiveData.info1.postValue("六秒钟后,修改了哦")
    20. }
    21. // -------------- 下面是 触发修改数据 的写法
    22. // lambda 写法如下 observe:
    23. MyLiveData.info1.observe(this, {
    24. })
    25. // lambda 写法如下 observeForever:
    26. MyLiveData.info1.observeForever({
    27. })
    28. // 详细写法如下 observe:
    29. MyLiveData.info1.observe(this, object : Observer {
    30. override fun onChanged(t: String?) {
    31. }
    32. })
    33. // 详细写法如下 observeForever:
    34. MyLiveData.info1.observeForever(object : Observer {
    35. override fun onChanged(t: String?) {
    36. }
    37. })
    38. }
    39. }

    2.使用方式二:

    MainActivity2.kt

    1. class MainActivity2 : AppCompatActivity() {
    2. override fun onCreate(savedInstanceState: Bundle?) {
    3. super.onCreate(savedInstanceState)
    4. setContentView(R.layout.activity_main2)
    5. val button = findViewById
    6. button.setOnClickListener {
    7. startService(Intent(this, MyService::class.java))
    8. Toast.makeText(MainActivity2@this, "推送服务器启动成功",
    9. Toast.LENGTH_SHORT).show()
    10. }
    11. MyLiveData.data1.observe(this, {
    12. Log.d("server", "界面可见,说明用户在查看微信列表界面啦,更新消息列表UI界
    13. 面:${it}")
    14. Toast.makeText(this, "更新消息列表UI界面成功:${it}",
    15. Toast.LENGTH_SHORT).show()
    16. })
    17. }
    18. }

    MyLiveData.kt

    1. object MyLiveData {
    2. // 这里为info1的MutableLiveData 懒加载初始化(懒加载:用到时才加载)
    3. val data1: MutableLiveData by lazy { MutableLiveData() }
    4. // 注意:这里会奔溃 因为是在 thread { 首次实例化MyLiveData对象的,而下面确实setValue就会奔溃
    5. /*init {
    6. data1.value = "default"
    7. }*/
    8. }

    MyService.kt

    1. class MyService : Service() {
    2. override fun onBind(intent: Intent): IBinder? = null
    3. override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int
    4. {
    5. thread {
    6. for (x in 1..100000) {
    7. Log.d("server", "服务器给推你推送消息啦(叮咚声响),消息内容是:${x}")
    8. MyLiveData.data1.postValue("服务器给推你推送消息啦,消息内容是:${x}")
    9. Thread.sleep(5000) // 2秒钟推一次
    10. }
    11. }
    12. return super.onStartCommand(intent, flags, startId)
    13. }
    14. }

    3.使用方式三(黏性):

    MainActivity3.kt

    1. class MainActivity3 : AppCompatActivity() {
    2. override fun onCreate(savedInstanceState: Bundle?) {
    3. super.onCreate(savedInstanceState)
    4. setContentView(R.layout.activity_main3)
    5. val button = findViewById
    6. button.setOnClickListener {
    7. MyLiveData.value1.value = "我就是我,不一样的烟火"
    8. startActivity(Intent(this, MainActivity4::class.java))
    9. }
    10. }
    11. }

    MainActivity4.kt

    1. class MainActivity4 : AppCompatActivity() {
    2. override fun onCreate(savedInstanceState: Bundle?) {
    3. super.onCreate(savedInstanceState)
    4. setContentView(R.layout.activity_main4)
    5. MyLiveData.value1.observe(this, {
    6. Toast.makeText(this, "观察者数据变化:$it", Toast.LENGTH_SHORT).show()
    7. })
    8. }
    9. }

    MyLiveData.kt

    1. object MyLiveData {
    2. // 这里为info1的MutableLiveData 懒加载初始化(懒加载:用到时才加载)
    3. val value1 : MutableLiveData by lazy { MutableLiveData() }
    4. }

    三、LiveData的源码原理解析

    1. MutableLiveData 

    继承了LiveData是一个可变的LiveData
    是一个被观察者,是一个数据持有者
    提供了 setValue 和 postValue方法,其中postValue可以在子线程调用
    postValue方法,我们下面会具体分析 

    1. public class MutableLiveData extends LiveData {
    2. /**
    3. * Creates a MutableLiveData initialized with the given {@code value}.
    4. *
    5. * @param value initial value
    6. */
    7. public MutableLiveData(T value) {
    8. super(value);
    9. }
    10. /**
    11. * Creates a MutableLiveData with no value assigned to it.
    12. */
    13. public MutableLiveData() {
    14. super();
    15. }
    16. @Override
    17. public void postValue(T value) {
    18. super.postValue(value);
    19. }
    20. @Override
    21. public void setValue(T value) {
    22. super.setValue(value);
    23. }
    24. }

    2.MutableLiveData的observe方法参数的this

    此接口是宿主生命周期的代表

    1. public interface LifecycleOwner{
    2. @NonNull Lifecycle getLifecycle();
    3. }

    3.MutableLiveData的observe方法参数的Observer

    Observer是一个观察者
    Observer中有一个回调方法,在 LiveData 数据改变时会回调此方法

    1. public interface Observer {
    2. /**
    3. * 当数据改变时调用。
    4. * @param t 新数据
    5. */
    6. void onChanged(T t);
    7. }

    4.源码分析

    首先我们上面示例中的 LiveData.observe()方法开始。

    1. class MainActivity : AppCompatActivity() {
    2. override fun onCreate(savedInstanceState: Bundle?) {
    3. super.onCreate(savedInstanceState)
    4. setContentView(R.layout.activity_main)
    5. val textView: TextView = findViewById(R.id.tv_textview)
    6. MyLiveData.info1.observe(this, {
    7. textView.text = it
    8. })
    9. thread {
    10. Thread.sleep(3000)
    11. MyLiveData.info1.postValue("三秒钟后,修改了哦")
    12. }
    13. thread {
    14. Thread.sleep(6000)
    15. MyLiveData.info1.postValue("六秒钟后,修改了哦")
    16. }
    17. }
    18. }

    我们点进observe方法中去它的源码

    5.LiveData源码

    1)在LiveData的observe方法中
    1. @MainThread
    2. public void observe(@NonNull LifecycleOwner owner, @NonNull Observersuper T>
    3. observer) {
    4. assertMainThread("observe");
    5. // 一:首先会通过LifecycleOwner获取Lifecycle对象然后获取Lifecycle 的State,如果是DESTROYED直接 return 了。忽略这次订阅
    6. if (owner.getLifecycle().getCurrentState() == DESTROYED) {
    7. // ignore
    8. return;
    9. }
    10. // 二:把LifecycleOwner和Observer包装成LifecycleBoundObserver对象,至于为什么包装成这个对象,我们下面具体讲,而且这个是重点。
    11. LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner,
    12. observer);
    13. // 三:把观察者存到 Map 中
    14. ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    15. // 四:之前添加过LifecycleBoundObserver,并且LifecycleOwner不是同一个,就抛异常
    16. if (existing != null && !existing.isAttachedTo(owner)) {
    17. throw new IllegalArgumentException("Cannot add the same observer"
    18. + " with different lifecycles");
    19. }
    20. if (existing != null) {
    21. return;
    22. }
    23. // 五:通过Lifecycle和添加 LifecycleBoundObserver观察者,形成订阅关系
    24. owner.getLifecycle().addObserver(wrapper);
    25. }

    到现在,我们知道了LiveData的observe方法中会判断 Lifecycle 的生命周期,
    会把LifecycleOwner和Observer包装成LifecycleBoundObserver对象,
    然后 Lifecycle().addObserver(wrapper) 
    Lifecycle 这个被观察者会在合适的时机 通知 观察者的回调方法。

    2)什么时候通知,怎么通知的呢?这个具体流程是什么,继续看下面代码
    1. thread {
    2. Thread.sleep(3000)
    3. MyLiveData.info1.postValue("三秒钟后,修改了哦")
    4. }
    5. thread {
    6. Thread.sleep(6000)
    7. MyLiveData.info1.postValue("六秒钟后,修改了哦")
    8. }

    在点击按钮的时候 LiveData会调用postValue ----> setValue方法,来更新最新的值,这时候我们
    的观察者Observer就会收到回调,来更新 TextView。
    所以接下来我们先看下 LiveData的setValue方法做了什么,LiveData还有一个postValue方法,我
    们也一并分析一下。

    6.LiveData的setValue与postValue

    1)setValue
    1. // LiveData.java
    2. @MainThread
    3. protected void setValue(T value){
    4. assertMainThread("setValue");
    5. mVersion++;
    6. mData=value;
    7. dispatchingValue(null); // 注意:这里的分发value值
    8. }

    调用了dispatchingValue方法,继续跟代码

    1. void dispatchingValue(@Nullable ObserverWrapper initiator) {
    2. if (mDispatchingValue) {
    3. mDispatchInvalidated = true;
    4. return;
    5. }
    6. mDispatchingValue = true;
    7. do {
    8. mDispatchInvalidated = false;
    9. if (initiator != null) { // 如果传递进来的 非null,就进此if
    10. considerNotify(initiator);
    11. 不管如何判断,都是调用了considerNotify() 方法
    12. initiator = null;
    13. } else { // 如果传递进来的 null,就进此if
    14. for (Iteratorsuper T>, ObserverWrapper>>
    15. iterator =
    16. mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
    17. considerNotify(iterator.next().getValue());
    18. 不管如何判断,都是调用了
    19. considerNotify() 方法
    20. if (mDispatchInvalidated) {
    21. break;
    22. }
    23. }
    24. }
    25. } while (mDispatchInvalidated);
    26. mDispatchingValue = false;
    27. }

    不管如何判断,都是调用了considerNotify()方法

    1. private void considerNotify(ObserverWrapper observer) {
    2. if (!observer.mActive) {
    3. return;
    4. }
    5. if (!observer.shouldBeActive()) {
    6. observer.activeStateChanged(false);
    7. return;
    8. }
    9. if (observer.mLastVersion >= mVersion) {
    10. return;
    11. }
    12. observer.mLastVersion = mVersion;
    13. //noinspection unchecked
    14. // 最终调用了observer.mObserver.onChanged((T) mData)方法,
    15. // 这个observer.mObserver就是我们的 Observer接口,然后调用它的onChanged方法。
    16. observer.mObserver.onChanged((T) mData);
    17. // 恭喜恭喜 :到现在整个被观察者数据更新通知观察者这个流程就通了。
    18. }
    2)postValue

    子线程发送消息通知更新 UI,嗯?Handler 的味道

    1. // LiveData.java
    2. protected void postValue(T value) {
    3. boolean postTask;
    4. synchronized (mDataLock) {
    5. postTask = mPendingData == NOT_SET;
    6. mPendingData = value;
    7. }
    8. if (!postTask) {
    9. return;
    10. }
    11. // 利用Handler切换到主线程去执行
    12. ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    13. }

    可以看到一行关键代码
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    点 postToMainThread 方法进去看下

    1. // ArchTaskExecutor.java
    2. privateTaskExecutor mDelegate;
    3. @Override
    4. public void postToMainThread(Runnable runnable) {
    5. mDelegate.postToMainThread(runnable);
    6. }

    看到 mDelegate 是 TaskExecutor对象,现在目标是看下 mDelegate 的具体实例对象是谁

    1. // ArchTaskExecutor.java
    2. private ArchTaskExecutor(){
    3. mDefaultTaskExecutor=new DefaultTaskExecutor();
    4. mDelegate=mDefaultTaskExecutor; // 目前的重点是看下DefaultTaskExecutor是个啥
    5. }

    然后看它的postToMainThread方法

    1. // DefaultTaskExecutor.java
    2. privatevolatileHandler mMainHandler;
    3. @Override
    4. public void postToMainThread(Runnable runnable) {
    5. if (mMainHandler == null) {
    6. synchronized (mLock) {
    7. if (mMainHandler == null) {
    8. // 实例了一个 Handler 对象,注意构造参数 Looper.getMainLooper() 是主线的 Looper。
    9. // 那么就可做到线程切换了。
    10. mMainHandler = new Handler(Looper.getMainLooper()); // 注意:这里主
    11. 线程已经切换过来了
    12. }
    13. }
    14. }
    15. //noinspection ConstantConditions
    16. // 调用post 方法 注意:重点看runnable,这里面就是真正主线程的执行功能了
    17. mMainHandler.post(runnable);
    18. }

    下面看下这个 Runnable
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    这里面的方法参数是mPostValueRunnable是个 Runnable,我们看下代码

    1. // LiveData.java
    2. private final Runnable mPostValueRunnable = new Runnable() {
    3. @Override
    4. public void run() {
    5. Object newValue;
    6. synchronized (mDataLock) {
    7. newValue = mPendingData;
    8. mPendingData = NOT_SET;
    9. }
    10. //noinspection unchecked
    11. // 注意:postValue方法其实最终调用也是setValue方法,然后和setValue方法走的流程就是一样的了,
    12. // 这个上面已经分析过了
    13. setValue((T) newValue);
    14. }
    15. };

    7.LifecycleBoundObserver

    我们要详细看一下LifecycleBoundObserver类了,它包装了LifecycleOwner和Observer,这就是
    接下来的重点内容了。

    1)observe
    1. @MainThread
    2. public void observe(@NonNull LifecycleOwner owner, @NonNull Observersuper T>
    3. observer) {
    4. assertMainThread("observe");
    5. if (owner.getLifecycle().getCurrentState() == DESTROYED) {
    6. // ignore
    7. return;
    8. }
    9. // 用LifecycleBoundObserver对LifecycleOwner 和 Observer进行了包装
    10. LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner,
    11. observer);
    12. ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    13. if (existing != null && !existing.isAttachedTo(owner)) {
    14. throw new IllegalArgumentException("Cannot add the same observer"
    15. + " with different lifecycles");
    16. }
    17. if (existing != null) {
    18. return;
    19. }
    20. owner.getLifecycle().addObserver(wrapper);
    21. }

    来看下LifecycleBoundObserver类,它是LiveData的内部类

    1. class LifecycleBoundObserver extends ObserverWrapper implements
    2. GenericLifecycleObserver {
    3. @NonNull
    4. final LifecycleOwner mOwner;
    5. LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observersuper T>
    6. observer) {
    7. super(observer);
    8. mOwner = owner;
    9. }
    10. }

    两个参数,一个 owner被成员变量mOwner存储,observer参数被ObserverWrapper的 mObserver存储。
    LifecycleEventObserver是LifecycleObserver的子接口里面有一个onStateChanged方法,这个方法会在 Activity、Fragment 生命周期回调时调用(这个和Lifecycle有关)
    ObserverWrapper 是Observer包装类

    2)ObserverWrapper

    活跃状态指的是 Activity、Fragment 等生命周期处于活跃状态

    1. private abstract class ObserverWrapper {
    2. final Observersuper T> mObserver;
    3. boolean mActive;
    4. int mLastVersion = START_VERSION;
    5. // 获取了我们的 Observer 对象,存储在 成员变量mObserver身上
    6. ObserverWrapper(Observersuper T> observer) {
    7. mObserver = observer;
    8. }
    9. // 抽象方法,当前是否是活跃的状态
    10. abstract boolean shouldBeActive();
    11. boolean isAttachedTo(LifecycleOwner owner) {
    12. return false;
    13. }
    14. void detachObserver() {
    15. }
    16. void activeStateChanged(boolean newActive) {
    17. if (newActive == mActive) {
    18. return;
    19. }
    20. // immediately set active state, so we'd never dispatch anything to inactive
    21. // owner
    22. mActive = newActive;
    23. boolean wasInactive = LiveData.this.mActiveCount == 0;
    24. LiveData.this.mActiveCount += mActive ? 1 : -1;
    25. if (wasInactive && mActive) {
    26. // 可以继承 LiveData 来达到扩展 LiveData 的目标,并且是在活跃的状态调用
    27. onActive();
    28. }
    29. if (LiveData.this.mActiveCount == 0 && !mActive) {
    30. // 可以继承 LiveData 来达到扩展 LiveData 的目标,并且是在非活跃的状态调用
    31. onInactive();
    32. }
    33. if (mActive) {
    34. // 活跃状态,发送最新的值,来达到通知的作用,dispatchingValue(this) 方法咋这么眼熟,
    35. // 对之前在 LiveData 调用 setValue 方法时,最终也会调用到此方法。
    36. // 那ObserverWrapper类中的dispatchingValue这个方法是在activeStateChanged方法中调用,
    37. // 那activeStateChanged啥时候调用呢?
    38. // 我来看下ObserverWrapper的子类也就是最重要的那个类LifecycleBoundObserver,
    39. // 现在看它的完整代码(看下面代码 LifecycleBoundObserver完整代码)
    40. dispatchingValue(this);
    41. }
    42. }
    43. }

    LifecycleBoundObserver完整代码

    1. class LifecycleBoundObserver extends ObserverWrapper implements
    2. GenericLifecycleObserver {
    3. @NonNull
    4. final LifecycleOwner mOwner;
    5. LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observersuper T>
    6. observer) {
    7. super(observer);
    8. mOwner = owner;
    9. }
    10. @Override
    11. boolean shouldBeActive() {
    12. // 判断当前的 Lifecycle 的生命周期是否是活跃状态,会在回调观察则 Observer 的时候进行判断,
    13. // 只有在活跃状态,才会回调观察者Observer的onChanged方法。
    14. return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    15. }
    16. @Override
    17. public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
    18. // onStateChanged每次 Activity、Fragment的生命周期回调的时候,都会走这个方法。
    19. // 获取Lifecycle对象然后获取Lifecycle 的State如果为DESTROYED则移除观察者,
    20. // 在 Activity、Fragment的生命周期走到 onDestroy 的时候,就会取消订阅,避免内存泄漏。
    21. if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
    22. removeObserver(mObserver);
    23. return;
    24. }
    25. // 调用父类ObserverWrapper 的activeStateChanged方法,
    26. // 层层调用到观察者Observer的onChanged方法。(自己看下源码一目了然)
    27. activeStateChanged(shouldBeActive());
    28. }
    29. @Override
    30. boolean isAttachedTo(LifecycleOwner owner) {
    31. return mOwner == owner;
    32. }
    33. @Override
    34. void detachObserver() {
    35. // 移除观察者Observer,解除订阅关系。
    36. mOwner.getLifecycle().removeObserver(this);
    37. }
    38. }

    四、自定义JLiveDataBus解决黏性问题

    JLiveDataBus.kt

    1. object JLiveDataBus {
    2. private const val TAG = "JLiveDataBus"
    3. private val busMap: MutableMap> by lazy { HashMap>() }
    4. @Synchronized
    5. fun with(key: String, type: Class<T>, isStick: Boolean = true): BusMutableLiveData {
    6. Log.d(TAG, "with isStick $isStick")
    7. if (!busMap.containsKey(key)) {
    8. busMap[key] = BusMutableLiveData(isStick)
    9. } else {
    10. (busMap[key] as BusMutableLiveData).isStick = isStick
    11. }
    12. return busMap[key] as BusMutableLiveData
    13. }
    14. class BusMutableLiveData<T> private constructor() : MutableLiveData() {
    15. // 启用粘性事件
    16. var isStick: Boolean = false
    17. // 次构造函数,必须调用主构造函数
    18. constructor(isStick: Boolean) : this() {
    19. Log.d(TAG, "constructor isStick $isStick")
    20. this.isStick = isStick
    21. }
    22. // 重写 增加hook
    23. override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
    24. super.observe(owner, observer)
    25. if (!isStick) {
    26. // 不启用粘性事件
    27. hook(observer = observer)
    28. Log.d(TAG, "不启动粘性事件")
    29. } else {
    30. Log.d(TAG, "启动粘性事件")
    31. }
    32. }
    33. private fun hook(observer: Observer<in T>) {
    34. // TODO 1.利用反射得到mLastVersion
    35. // 获取到LiveData类中的mObservers对象
    36. val liveDataClass = LiveData::class.java
    37. val mObserversField: Field = liveDataClass.getDeclaredField("mObservers")
    38. // 设置权限,私有修饰也可以访问
    39. mObserversField.isAccessible = true
    40. // 获取到mObservers这个成员变量的对象
    41. val mObservers: Any = mObserversField.get(this)
    42. // 获取到mObservers的class对象
    43. val mObserversClass: Class<*> = mObservers.javaClass
    44. // 获取到mObservers对象的get方法
    45. val get: Method = mObserversClass.getDeclaredMethod("get", Any::class.java)
    46. get.isAccessible = true
    47. // 执行get方法
    48. val invokeEntry: Any = get.invoke(mObservers, observer)
    49. // 获取到entry中的value
    50. var observerWraper: Any? = null
    51. if (invokeEntry != null && invokeEntry is Map.Entry<*, *>) {
    52. observerWraper = invokeEntry.value
    53. }
    54. if (observerWraper == null) {
    55. throw NullPointerException("observerWraper is null.")
    56. }
    57. // 获取到observerWraper的类对象
    58. val supperClass: Class<*> = observerWraper.javaClass.superclass!!
    59. val mLastVersion: Field = supperClass.getDeclaredField("mLastVersion")
    60. mLastVersion.isAccessible = true
    61. // TODO 2.得到mVersion
    62. val mVersion: Field = liveDataClass.getDeclaredField("mVersion")
    63. mVersion.isAccessible = true
    64. // TODO 3.mLastVersion = mVersion
    65. val mVersionValue: Any = mVersion.get(this)
    66. mLastVersion.set(observerWraper, mVersionValue)
    67. }
    68. }
    69. }

    BusActivity.kt

    1. class BusActivity : AppCompatActivity() {
    2. private lateinit var binding: ActivityBusBinding
    3. override fun onCreate(savedInstanceState: Bundle?) {
    4. super.onCreate(savedInstanceState)
    5. binding = ActivityBusBinding.inflate(layoutInflater)
    6. setContentView(binding.root)
    7. JLiveDataBus.with("test1", String::class.java, false).observe(this) {
    8. binding.busTv.text = it
    9. }
    10. thread {
    11. Thread.sleep(2000)
    12. JLiveDataBus.with("test1", String::class.java).postValue("新数据")
    13. }
    14. }
    15. }

    startActivity

    1. JLiveDataBus.with("test1", String::class.java).value = "老数据"
    2. textView.setOnClickListener {
    3. startActivity(Intent(activity, BusActivity::class.java))
    4. }

    由于我们在BusActivity使用的是不启用粘性,JLiveDataBus.with("test1", String::class.java, false).observe(this),所以当BusActivity启动时不会调用binding.busTv.text = "老数据",延迟2S后,正常接收到启动后的 新数据。

  • 相关阅读:
    VSCode里使用条件断点(基于GDB)
    一键帮您解决win11最新版画图工具难用问题!
    6.5 - 万维网
    OpenCV之GOTURN目标追踪
    TFT-LCD显示中英文
    http客户端Feign
    QT-串口工具
    (二)Easyexcel 的使用(读取数据到map集合中)
    python 下载图片按图片地址路径创建对应文件夹
    第三章 MATLAB的使用
  • 原文地址:https://blog.csdn.net/sziitjin/article/details/132943143