简介
背景
这几年 MVP 架构在安卓界非常流行,几乎已经成为主流框架,它让业务逻辑 和 UI操作相对独立,使得代码结构更清晰。
MVVM 在前端火得一塌糊涂,而在安卓这边却基本没见到几个人在用,看到介绍 MVVM 也最多是讲 DataBinding 或 介绍思想的。偶尔看到几篇提到应用的,还是对谷歌官网的Architecture Components 文章的翻译。
相信大家看别人博客或官方文档的时候,总会碰到一些坑。要么入门教程写得太复杂(无力吐槽,前面写一堆原理,各种高大上的图,然并卵,到实践部分一笔带过,你确定真的是入门教程吗)。要么就是简单得就是一个 hello world,然后就没有下文了(看了想骂人)。
实在看不下去的我,决定插手你的人生。
目录
《安卓-深入浅出MVVM教程》大致分两部分:应用篇、原理篇。
采用循序渐进方式,内容深入浅出,符合人类学习规律,希望大家用最少时间掌握 MVVM。
应用篇:
01 Hello MVVM (快速入门)
02 Repository (数据仓库)
03 Cache (本地缓存)
04 State Lcee (加载/空/错误/内容视图)
05 Simple Data Source (简单的数据源)
06 Load More (加载更多)
07 DataBinding (数据与视图绑定)
08 RxJava2
09 Dragger2
10 Abstract (抽象)
11 Demo (例子)
12-n 待定(欢迎 github 提建议)
原理篇
01 MyLiveData(最简单的LiveData)
02-n 待定(并不是解读源码,那样太无聊了,打算带你从0撸一个 Architecture)
关于提问
本人水平和精力有限,如果有大佬发现哪里写错了或有好的建议,欢迎在本教程附带的 github仓库 提issue。
What?为什么不在博客留言?考虑到国内转载基本无视版权的情况,一般来说你都不是在源出处看到这篇文章,所以留言我也一般是看不到的。
教程附带代码
https://github.com/ittianyu/MVVM
应用篇放在 app 模块下,原理篇放在 implementation 模块下。
每一节代码采用不同包名,相互独立。
前言
这一节是在 04 节的基础上开始的,请大家拷贝一份之前04的项目。(注意,后面几节也是从 04 的项目开始,所以建议保留一份不动)
先修要求
- 会使用 RxJava2
环境配置
加入 RxJava2 和 retrofit LiveData 的适配器库
// RxJava2
compile 'io.reactivex.rxjava2:rxjava:2.1.5'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
// retrofit-adapter
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
// LiveData adapter rxjava2
compile "android.arch.lifecycle:reactivestreams:$rootProject.lifecycle"
retrofit-adapter-rxjava2
要适配 retrofit,只需要在 RetrofitFactory 中加入适配器
retrofit = new Retrofit.Builder()
.baseUrl(HOST)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
retrofit api
现在我们把之前的 Call 改为 Observable 或者 Flowable
public interface UserApi {
@GET("/users/{username}")
Observable queryUserByUsername(@Path("username") String username);
}
LiveDataReactiveStreams
官方给我们提供了 LiveData 和 RxJava 源的转换器
实际上就是简单的两个方法。
Publisher toPublisher(LifecycleOwner lifecycle, LiveData liveData)
LiveData fromPublisher(final Publisher publisher)
有了它就可以把 Flowable
到这里,似乎已经讲完了。
但是,你有没有注意到,Retrofit 接口返回的是 Flowable
瞬间尴尬,怎么办?急!在线等!
ObservableLceeLiveData
一开始我尝试着将 LiveData
然后我就点开了 LiveDataReactiveStreams 的代码,发现竟然很简单。所以我就知道,是时候自己写一个转换器了。
这里我写的是 Observable
原理其实很简单,订阅 Observable,然后在对应的回调方法中设置值就好
class ObservableLceeLiveData extends LiveData> {
private WeakReference mDisposableRef;
private final Observable mObservable;
private final Object mLock = new Object();
ObservableLceeLiveData(@NonNull final Observable observable) {
mObservable = observable;
}
@Override
protected void onActive() {
super.onActive();
mObservable.subscribe(new Observer() {
@Override
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
// Don't worry about backpressure. If the stream is too noisy then
// backpressure can be handled upstream.
synchronized (mLock) {
mDisposableRef = new WeakReference<>(d);
}
postValue(Lcee.loading());
}
@Override
public void onNext(@io.reactivex.annotations.NonNull T t) {
if (null == t)
postValue(Lcee.empty());
else
postValue(Lcee.content(t));
}
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable t) {
synchronized (mLock) {
mDisposableRef = null;
}
// Errors should be handled upstream, so propagate as a crash.
// throw new RuntimeException(t);
postValue(Lcee.error(t));
}
@Override
public void onComplete() {
synchronized (mLock) {
mDisposableRef = null;
}
}
});
}
@Override
protected void onInactive() {
super.onInactive();
synchronized (mLock) {
WeakReference subscriptionRef = mDisposableRef;
if (subscriptionRef != null) {
Disposable subscription = subscriptionRef.get();
if (subscription != null) {
subscription.dispose();
}
mDisposableRef = null;
}
}
}
}
为了便于调用,我封装了一个工厂类
public class LiveDataObservableAdapter {
public static LiveData> fromObservableLcee(final Observable observable) {
return new ObservableLceeLiveData<>(observable);
}
}
RemoteUserDataSource
因为有了转换器,下面的工作就很简单了。
之前的那么多行代码才得到 LiveData,现在几行就实现了。
是不是舒畅了很多。
public class RemoteUserDataSource implements UserDataSource {
private static final RemoteUserDataSource instance = new RemoteUserDataSource();
private RemoteUserDataSource() {
}
public static RemoteUserDataSource getInstance() {
return instance;
}
private UserApi userApi = RetrofitFactory.getInstance().create(UserApi.class);
@Override
public LiveData> queryUserByUsername(String username) {
return LiveDataObservableAdapter.fromObservableLcee(
userApi.queryUserByUsername(username)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
);
}
}
总结
接入 RxJava2,使得 RemoteUserDataSource 里面的代码减少了,可以说大大减少了重复性代码。
实际上外界还流传另外一种写法,不用 LiveData,用 RxJava 来代替,但这样需要你在 Activity 中处理生命周期。我觉得不够优雅,就不讲了。