最后
文章所有资料全部已经打包整理好,另外小编手头上整理了大量Android架构师全套学习资料,Android核心高级技术PDF文档+全套高级学习资料+视频+2021 BAT 大厂面试真题解析
资料展示:
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
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,在调用 public 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_DESTROY
时 removeObserver
。
接下来就要考虑激活和非激活的状态了,既然用了 observeForever
,那每次事件都会有回调,这时候如果 Lifecycle
处于激活状态,那可以直接把事件发出去。但如果非激活,不能直接把事件发出去,又不能丢,那我们就需要先把事件存起来,然后在 Lifecycle
变为激活状态时再把存起来的事件发送出去。简单画了下流程图。
/**
- 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 之后就是激活状态了,如果之前存的有数据,就发送出去
*/
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
private void onEvent(LifecycleOwner owner, Lifecycle.Event event) {
if (owner != mOwner) {
return;
}
if (event == Lifecycle.Event.ON_START || event == Lifecycle.Event.ON_RESUME) {
for (int i = 0; i < mPendingData.size(); i++) {
mObserver.onChanged(mPendingData.get(i));
}
mPendingData.clear();
}
}
/**
- onDestroy 时解除各方的观察和绑定,并清空数据
*/
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
private void onDestroy() {
mLiveData.removeObserver(this);
mLiveData = null;
mOwner.getLifecycle().removeObserver(this);
mOwner = null;
mPendingData.clear();
mObserver = null;
}
public static void bind(@NonNull LiveData liveData,
@NonNull LifecycleOwner owner,
@NonNull Observer<? super T> observer) {
if (owner.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
return;
}
new LiveEventObserver<>(liveData, owner, observer);
}
}
3.4、保证 LiveData 的事件更新
3.1 也说过要自己处理 postValue,其次要保证用我们自己定义的观察者,需要重写 public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)。
/**
- 用作事件总线的 {@link MutableLiveData}
- @see AsEventBus
写在最后
在技术领域内,没有任何一门课程可以让你学完后一劳永逸,再好的课程也只能是“师傅领进门,修行靠个人”。“学无止境”这句话,在任何技术领域,都不只是良好的习惯,更是程序员和工程师们不被时代淘汰、获得更好机会和发展的必要前提。
如果你觉得自己学习效率低,缺乏正确的指导,可以一起学习交流!
加入我们吧!群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
业规划。35岁后的你只会比周围的人更值钱。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!