MVVM 架构图
谈到 MVVM 架构,不得不祭出官方的架构图,架构图能帮助我们更好地理解,如下所示:
MVVM 和 MVP 的区别
MVP 中 V 层和 P 层互相持有对方的引用,在V 层调用 P 层逻辑后,P 层回调V 层的相应方法更新 UI。
而在 MVVM 中,上层只依赖直接下层,不能跨层持有引用,那 View 层调用 ViewModel 处理数据后,又如何更新自己呢?
答案就在 ViewModel 中的 LiveData,这是一种可观察的数据类型,在 View 层中观察者 Observer 对需要的数据进行订阅,当数据发生变化后,观察者 Observer 的回调方法 onChanged() 中会收到新的数据,从而可以更新 UI。
Jetpack 架构组件
Jetpack 是 Google 为我们提供的架构组件,对于这些组件,我有以下理解和使用心得:
DataBinding
适用于数据繁杂的页面,可以减少大量 java 代码。xml 中可以做出类似于VUE 那样的数据双向绑定。同时可以直接调用控件id名称直接写UI逻辑代码不用写findviewById,也不用通过butterknife来注解实现findviewById的节省。
ViewModel
管理 Activity 或 Fragment 的数据
创建于Activity 或 Fragment 内,页面被销毁前,ViewModel 会一直存在
如果因配置变化导致页面销毁,ViewModel 不会销毁,它会被用于新的页面实例
一般在 ViewModel 中配合 LiveData 使用
一般用 ViewModelProviders 获取 ViewModelProvider,再用它的 get() 方法获取 ViewModel
在 get() 方法中会调用 Factory 的 create() 方法创建 ViewModel
Lifecycles
管理你的 Activity 和 Fragment 生命周期。
不用再通过写回调监听来感知Activity 和 Fragment 生命周期的变化来做相应的处理动作
LiveData
基于生命周期的消息订阅组件,不会发生内存泄漏,不用反注册。
MVVM 案例实战
下面根据我的开源项目 Jetpack_MVVM进一步讲解 MVVM 架构的运用,以下所有代码均来自于该项目
1、基类封装
专门针对MVVM模式打造的BaseActivity、BaseFragment、BaseViewModel,在View层中不再需要定义ViewDataBinding和ViewModel,直接在BaseActivity、BaseFragment上限定泛型即可使用。
public abstract class BaseActivity<V extends ViewDataBinding, VM extends BaseViewModel> extends RxAppCompatActivity implements LifecycleProvider<ActivityEvent> {
protected V binding;
protected VM viewModel;
/**
* 注入绑定
*/
private void initViewDataBinding(Bundle savedInstanceState) {
//DataBindingUtil类需要在project的build中配置 dataBinding {enabled true }, 同步后会自动关联android.databinding包
binding = DataBindingUtil.setContentView(this, initContentView(savedInstanceState));
viewModelId = initVariableId();
viewModel = initViewModel();
if (viewModel == null) {
Class modelClass;
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
modelClass = (Class) ((ParameterizedType) type).getActualTypeArguments()[1];
} else {
//如果没有指定泛型参数,则默认使用BaseViewModel
modelClass = BaseViewModel.class;
}
viewModel = (VM) createViewModel(modelClass);
}
...........................
}
/**
* 创建ViewModel
*
* @param <T>
* @return
*/
protected <T extends ViewModel> T createViewModel(@NonNull Class<T> modelClass) {
if (mActivityProvider == null) {
mActivityProvider = new ViewModelProvider(this);
}
return mActivityProvider.get(modelClass);
}
...............
}
2、网络请求框架封装
retrofit+okhttp+rxJava负责网络请求;gson负责解析json数据;rxlifecycle负责管理view的生命周期;与网络请求共存亡;
RetrofitClient
NetWorkManager
这两个类分别封装了Retrofit的相关配置和具体的使用方法。
RetrofitClient 中对相关参数进行相关初始化配置,拦截配置,以及参数加密配置。
public class RetrofitClient {
//超时时间
private static final int DEFAULT_TIME_OUT = 10;//超时时间 70s
private static final int DEFAULT_READ_TIME_OUT = 10;
//缓存时间
private static final int CACHE_TIMEOUT = 10 * 1024 * 1024;
//服务端根路径
public static String baseUrl = "http://rap2.taobao.org:38080/app/mock/259908/";
private static Context mContext = App.getContext();
private static OkHttpClient okHttpClient;
private static Retrofit retrofit;
private Cache cache = null;
private File httpCacheDirectory;
private static class SingletonHolder {
private static RetrofitClient INSTANCE = new RetrofitClient();
}
public static RetrofitClient getInstance() {
return SingletonHolder.INSTANCE;
}
private RetrofitClient() {
this(baseUrl, null);
}
private RetrofitClient(String url, Map<String, String> headers) {
if (TextUtils.isEmpty(url)) {
url = baseUrl;
}
if (httpCacheDirectory == null) {
httpCacheDirectory = new File(mContext.getCacheDir(), "goldze_cache");
}
try {
if (cache == null) {
cache = new Cache(httpCacheDirectory, CACHE_TIMEOUT);
}
} catch (Exception e) {
LogUtils.e("Could not create http cache", e);
}
HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory();
okHttpClient = new OkHttpClient.Builder()
.cookieJar(new CookieJarImpl(new PersistentCookieStore(mContext)))
.cache(cache)
.addInterceptor(new BaseInterceptor(headers))
.addInterceptor(new CacheInterceptor(mContext))
.addInterceptor(commonHeader())
.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
.addInterceptor(new LoggingInterceptor
.Builder()//构建者模式
.loggable(BuildConfig.