我是靠谱客的博主 凶狠导师,最近开发中收集的这篇文章主要介绍Android开发把-LiveData-用于事件传递那些坑,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

2.3、LiveData 就不是为传递事件准备的

从上面两点也可以看出,LiveData (或者说它的观察者) 在观察者激活之前并不关心中间经历过多少次数据变更,它只会在某个观察者激活时,传递给他最新的值,中间的值都不会起作用。
当然 LiveData 的设计也不是为了传递事件的,它是为了反应 View 当前状态的,View 层只需要根据当前 LiveData 的值去渲染数据就行,非激活状态时 View 都不可见,就算更新了也没意义。
我最开始也是觉得 LiveData 用到了观察者模式,而且可以进 《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》开源 行一些不同 Fragment 之间数据通讯,就想到了事件总线,现在想想当时还是 too young too naive。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vdjk3LMX-1649940725173)(//upload-images.jianshu.io/upload_images/17428135-e1c09fe77a23f567.png?imageMogr2/auto-orient/strip|imageView2/2/w/289/format/webp)]

当然,也不是说 LiveData 也不是没救了,有谷歌给我们提供了强大的 Lifecycle 库,我们完全可以自己造一个不会丢事件的 LiveData

3、打造一个不会丢事件的 LiveData

LiveData 的其他功能做的很完善,只是会丢事件,我们要改造就要就针对上面的问题逐个击破。

3.1、postValue 的问题

对于 postValue 的问题,既然它最后也是调用的 setValue,丢数据是因为只抛了一次 Runable,那我们就自己每次都往主线程抛一个 Runable 就能解决这个问题

/**

  • LiveData 相关的工具类,简化 LiveData 操作
  • @author funnywolf
  • @since 2019-04-22
    /
    public class LiveDataUtils {
    private static Handler sMainHandler;
    /
    *
  • 用 setValue 更新 MutableLiveData 的数据,如果在子线程,就切换到主线程
    */
    public static void setValue(MutableLiveData mld, T d) {
    if (mld == null) {
    return;
    }
    if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
    mld.setValue(d);
    } else {
    postSetValue(mld, d);
    }
    }

/**

  • 向主线程的 handler 抛 SetValueRunnable
    */
    public static void postSetValue(MutableLiveData mld, T d) {
    if (sMainHandler == null) {
    sMainHandler = new Handler(Looper.getMainLooper());
    }
    sMainHandler.post(SetValueRunnable.create(mld, d));
    }

private static class SetValueRunnable implements Runnable {
private final MutableLiveData liveData;
private final T data;

private SetValueRunnable(@NonNull MutableLiveData liveData, T data) {
this.liveData = liveData;
this.data = data;
}

@Override
public void run() {
liveData.setValue(data);
}

public static SetValueRunnable create(@NonNull MutableLiveData liveData, T data) {
return new SetValueRunnable<>(liveData, data);
}
}
}

3.2、非激活状态的问题

其实我觉得这个问题的主要「责任」并不在 LiveData,而是在它的观察者,「是你告诉我你非激活的呀,那我怎么给你发数据呢,我发给你,万一你出问题了呢,那到底谁负责?」。
我们常用的观察者其实是 LifecycleBoundObserver,在调用 publ Android开源项目:ali1024.coding.net/public/P7/Android/git ic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) 会自动帮我们封装一个这样的观察者,而它会根据 LifecycleOwner 的生命周期呈现出「激活」和「非激活」状态。

// LifecycleBoundObserver
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

LiveData 默认的还有另外一种观察者 AlwaysActiveObserver,它是我们在调用 public void observeForever(@NonNull Observer<? super T> observer) 时生成的,顾名思义它会一直处于激活状态,LiveData 当然也不会替我们管理这样观察者的生命周期,我们需要在不使用时手动调用 public void removeObserver(@NonNull final Observer<? super T> observer) 移除观察者,否则可能会内存泄漏。

// AlwaysActiveObserver
boolean shouldBeActive() {
return true;
}

这个 AlwaysActiveObserver 看样子能够解决我们的问题,他一直处于激活状态,那所有的事件都会回调给他,但是需要我们自己管理生命周期。这不是开历史倒车吗?好不容易有生命周期感知了,现在又要自己手动搞?

3.3、造一个生命周期感知的还不丢事件的观察者

手动管理生命周期是绝对不能忍的,AlwaysActiveObserver 可以解决刚才说的问题,那我们就造一个新的观察者来管理 observeForever 和 removeObserver 的问题。既然要造,那就造个好用的,首先事件一定不能丢,要不就没意义了;而且生命周期要观察者自己管理,不能只是简单的 observeForever 和 removeObserver,非激活状态之类的也要考虑进去。
既然要管理生命周期,那就不得不用到 LifecycleOwner、Lifecycle,然后自己观察 LifecycleOwner 的 Lifecycle。

/**

  • Marks a class as a LifecycleObserver. It does not have any methods, instead, relies on
  • {@link OnLifecycleEvent} annotated methods.
  • @see Lifecycle Lifecycle - for samples and usage patterns.
    */
    @SuppressWarnings(“WeakerAccess”)
    public interface LifecycleObserver {

}

Lifecycle 对外只给了这个接口,并不含有任何回调,我们需要用注释里说的 OnLifecycleEvent 注解来标记相应的函数,Lifecycle 会通过反射拿到标记的函数,然后生成对应的适配器,感兴趣的可以看下 Lifecycling.getCallback 函数。比如我们可以这样用

public class Observer implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
private void onStart() {
doSomethingOnStart();
}
}

拿到生命周期后,我们就可以在一开始 observeForever,在 Lifecycle.Event.ON_DESTROYremoveObserver
接下来就要考虑激活和非激活的状态了,既然用了 observeForever,那每次事件都会有回调,这时候如果 Lifecycle 处于激活状态,那可以直接把事件发出去。但如果非激活,不能直接把事件发出去,又不能丢,那我们就需要先把事件存起来,然后在 Lifecycle 变为激活状态时再把存起来的事件发送出去。简单画了下流程图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xEVwEtDZ-1649940725176)(//upload-images.jianshu.io/upload_images/17428135-1f59518e4ddfad46.png?imageMogr2/auto-orient/strip|imageView2/2/w/680/format/webp)]

/**

  • LiveData 用作事件传递时的观察者
  • 保证所有事件不丢失,保存非激活状态的事件,并能够在激活状态回调,且没有内存泄漏
  • @see AsEventBus
  • @author funnywolf
  • @since 2019-05-18
    */
    public class LiveEventObserver implements LifecycleObserver, Observer {
    private LiveData mLiveData;
    private LifecycleOwner mOwner;
    private Observer<? super T> mObserver;

private final List mPendingData = new ArrayList<>();

public LiveEventObserver(LiveData liveData, LifecycleOwner owner, Observer<? super T> observer) {
mLiveData = liveData;
mOwner = owner;
mObserver = observer;
mOwner.getLifecycle().addObserver(this);
mLiveData.observeForever(this);
}

/**

  • 在生命周期结束前的任何时候都可能会调用
    */
    @Override
    public void onChanged(@Nullable T t) {
    if (isActive()) {
    // 如果是激活状态,就直接更新
    mObserver.onChanged(t);
    } else {
    // 非激活状态先把数据存起来
    mPendingData.add(t);
    }
    }

/**

  • @return 是否是激活状态,即 onStart 之后到 onPause 之前
    */
    private boolean isActive() {
    return mOwner.getLifecycle().getCurrentState()
    .isAtLeast(Lifecycle.State.STARTED);
    }

/**

  • onStart 之后就是激活状态了,如果之前存的有数据,就发送出去
    */

总结

首先是感觉自己的基础还是不够吧,大厂好像都喜欢问这些底层原理。

另外一部分原因在于资料也还没有看完,一面时凭借那份资料考前突击恶补个几天居然也能轻松应对(在这里还是要感谢那份资料,真的牛),于是自我感觉良好,资料就没有怎么深究下去了。

之前的准备只涉及了Java、Android、计网、数据结构与算法这些方面,面对面试官对其他基础课程的考察显得捉襟见肘。

下一步还是要查漏补缺,进行针对性复习。

最后的最后,那套资料这次一定要全部看完,是真的太全面了,各个知识点都涵盖了,几乎我面试遇到的所有问题的知识点这里面都有!希望大家不要犯和我一样的错误呀!!!一定要看完!


要全部看完,是真的太全面了,各个知识点都涵盖了,几乎我面试遇到的所有问题的知识点这里面都有!希望大家不要犯和我一样的错误呀!!!一定要看完!**
[外链图片转存中…(img-Q4Xd6ApI-1649940725177)]

[外链图片转存中…(img-Z95tbp47-1649940725177)]

[外链图片转存中…(img-pueMXlzq-1649940725178)]

最后

以上就是凶狠导师为你收集整理的Android开发把-LiveData-用于事件传递那些坑的全部内容,希望文章能够帮你解决Android开发把-LiveData-用于事件传递那些坑所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(72)

评论列表共有 0 条评论

立即
投稿
返回
顶部