3月份快结束了,天气也渐渐变暖,希望2020年android行情也能够逐渐回暖吧,等待之余,我们也要不断的提升自己的技术,跟上技术更新的步伐。这不眼看着2020年Google IO大会即将发布新的功能,android10.0系统还没有玩熟,android11即将来临。是不是很可怕,是不是瞬间感觉android开发好痛苦,不要慌!!!饭要一口一口吃,路要一步一步走。是不是有些同学,对AAC(android架构组件)还没有真正的使用到项目中,是不是还在使用MVP设计模式开发。读过这篇文章,就会让你从此爱上MVVM模式。
一、MVC、MVP、MVVM对比
- MVC :与MVP最大区别在于activity是作为Controller层存在,这样就会导致activity的代码量十分臃肿,不易于维护。
- MVP:activity与布局作为V层,业务逻辑放在M层进行处理,通过P层接收V层的请求,然后将请求交给M层处理,将处理结果通过P层回到给V层。这种方式,在业务量很大的时候,会导致P层回调给V层的接口数量大量增加,导致接口地狱。
- MVVM:需要借助dataBinding,V层代表布局文件,我们可以在布局文件中添加逻辑代码,VM层负责业务交互,需要继承ViewModel。并与V层建立数据绑定,M层负责业务的处理。解决接口地狱问题,代码量减少,能够灵活地控制activity相关的生命周期。当然,目前发现的缺点就是会产生很多的中间类,apk体积会相应增加。随着布局的增加,编译速度也会越来越慢。
二、4个现代化
前不久看到一篇文章,说到一个完整的app应该包括4个"现代化"
- 层次化:各个模块的相互依赖关系,主次分明。能够快速切换组件环境和集成环境。
- 模块化:业务模块,base模块、common模块、网络模块等
- 控件化:自定义控件
- 插件化:动态加载的未安装的apk文件
我认为这种说法是正确的,区分这些能够加快代码的开发,以及功能之间的解耦。
1、层次化
这里其实最重要的就是gradle的配置,自定义config.gradle。把通用的gradle配置和第三方依赖放进来:
ext {
//定以变量,决定当前环境是集成环境还是组件化环境
//集成环境:把所有的module作为library打包到app中,不可单独运行
//组件化环境:就是可以单独运行的module
isRelease = true
//配置defaultConfig下的信息
versionConfig = [
"compileSdkVersion": 29,
"buildToolsVersion": "29.0.2",
"minSdkVersion" : 21,
"targetSdkVersion" : 29,
"versionCode" : 1,
"versionName" : "1.0"
]
//配置appId 就是applicationId
appId = [
"app" : "com.xinyartech.mymvvmmaster",
"main": "com.xinyartech.main",
]
appcompatVersion = "1.1.0"
retrofitVersion = "2.6.2"
arouteVersion = "1.4.1"
glideVersion = "4.11.0"
//测试版本和发布版本url地址
url = [
"debug" : "http://www.baidu.com",
"release": "http://www.google.com"
]
//配置第三方依赖
dependencies = [
"appcompat" : "androidx.appcompat:appcompat:$rootProject.appcompatVersion",
//网络
"rxjava2" : 'io.reactivex.rxjava2:rxjava:2.2.12',
"rxandroid" : 'io.reactivex.rxjava2:rxandroid:2.1.1',
"retrofit2_adapter" : "com.squareup.retrofit2:adapter-rxjava2:$rootProject.retrofitVersion",
"okhttp_log_interceptor": 'com.squareup.okhttp3:logging-interceptor:3.9.0',
"retrofit2_convert" : "com.squareup.retrofit2:converter-gson:$rootProject.retrofitVersion",
"retrofit2" : "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion",
//解析
"gson" : 'com.google.code.gson:gson:2.8.6',
"commonstool" : 'org.apache.commons:commons-lang3:3.7',
//动画
"lottie" : 'com.airbnb.android:lottie:2.8.0',
//错误界面
"loadsir" : 'com.kingja.loadsir:loadsir:1.3.6',
//生命周期
"lifecycle_extensions" : 'android.arch.lifecycle:extensions:1.1.1',
"lifecycle_viewmodel" : 'androidx.lifecycle:lifecycle-viewmodel:2.2.0',
//ARouter
"aroute" : "com.alibaba:arouter-api:$rootProject.arouteVersion",
//glide
"glide" : "com.github.bumptech.glide:glide:$rootProject.glideVersion",
//recyclerView
"recyclerview" : "androidx.recyclerview:recyclerview:$rootProject.appcompatVersion"
]
apts = [
"aroute_compiler": 'com.alibaba:arouter-compiler:1.2.2',
"glide_compiler" : "com.github.bumptech.glide:compiler:$rootProject.glideVersion"
]
}
然后不要忘记在工程的build.gradle文件第一行添加一句
apply from: "config.gradle"
buildscript{
xxx
}
allprojects{
xxx
}
这样才能在各个模块下使用ext扩展名。如何使用呢? 比如我在主模块app下使用,在app的build.gradle中添加如下:
def versionConfig = rootProject.ext.versionConfig
xxx
android {
compileSdkVersion versionConfig.compileSdkVersion
xxx
}
这样就可以通过自定义变量进行赋值了。
2、模块化
首先看一下整个app模块的截图:
这一块也是我们研究的重中之重。
2.1 网络模块network
这里主要是对Okhhtp、rxjava以及retrofit进行了二次封装,方便调用。举个例子,调用一个网络请求接口:
NetworkApi
.getInstance()
.getService(IMainService.class)
.getNewsList("5572a108b3cdc86cf39001cd", "国内焦点", "1")
.compose(
NetworkApi.getInstance().applySchedulers(new BaseObserver<MainBean>(this,this))
);
入口类是 NetworkApi.java,伪代码如下:
public class NetworkApi{
getInstance(){
xxx
}
public <T> T getService(Class<T> service) {
return getInstance().getRetrofit(service).create(service);
}
}
getService返回的是一个接口。负责retrofit相关的网络请求路径及参数进行统一配置。这里重点关注applySchedulers 和 BaseObserver。
(1)applySchedulers
/**
* 统一处理错误 、线程切换
*/
public <T> ObservableTransformer<T, T> applySchedulers(final BaseObserver<T> observer) {
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
Observable<T> observable = (Observable<T>) upstream
.subscribeOn(Schedulers.io(