目前的项目结构图置顶:Demo的Github地址: github.com/Dawish/Goog…
0-演示项目MVVM组件化架构图我前面对比了MVC和MVP《两张图看懂Android开发中MVC与MVP的区别》,可以相对于
我们的
- MVC
是有多优越,但是Android开发现在已经开始流行了
- MVP
,前不久google官方发布了MVVM的正式库。官方的正式MVVM库主要包括下面四个: 1-正式MVVM库组件
- MVVM
其中只有
是MVVM结构中的一个组件,其他的三个都是辅助性质的。
- ViewModel
就是处理UI界面的生命周期,在26版本以后的Support库中,
- lifecycles
和
- AppCompatActivity
中都实现了
- SupportActivity
,内部已经对UI界面的生命周期做了处理了。
- LifecycleOwner
是一个抽象类,我们可以存放UI页面需要的数据,就是把数据包装在
- LiveData
中了,我们可以观测
- LiveData
中的数据变化,但是
- LiveData
是跟UI的生命周期关联的,当UI页面销毁了,
- LiveData
的数据变化回调是不会执行的。
- LiveData
就是一个sqlite数据持久化库,我们也可以使用别的ORM库。
- Room
《两张图看懂Android开发中MVC与MVP的区别》 前面两张图真是了MVC和MVP的区别,我这里也来一张图看看MVVM:
2-MVVM架构看上图
和
- Model
是不会发生关系的,
- View
是把View和Model关联起来的加工厂: 3-ViewModel工厂
- ViewModel
和
- View
双向绑定,一方的改变都会影响另一方,开发者不用再去手动修改UI的数据。额,互相自动的。
- Model
也不需要
- findViewById
,不需要拿到具体的
- butterknife
去设置数据绑定监听器等等,这些都可以用
- View
完成。是不是很舒服
- DataBinding
和
- View
的双向绑定是支持生命周期检测的,不会担心页面销毁了还有回调发生,这个由
- Model
完成。
- lifeCycle
一样导致
- MVC
中代码量巨大,也不会像
- Activity
一样出现大量的
- MVP
和
- View
接口。项目结构更加低耦合。
- Presenter
下图是项目模块和工程之间的依赖关系:
4-MVVM组件化示例项目架构图下图是工程Android Studio中的目录结构:
:第三方build.gradle依赖,本项目主要有
- lib_opensource
、
- support
、
- lifecycle
、
- room
、
- fresco
、
- retrofit
、
- okhttp
、
- RxJava
这些。
- ARouter
: 存放MVVM中的
- lib_coremodel
和
- Model
两个模块,就是数据的处理和数据与UI页面的绑定。依赖
- ViewModel
库。
- lib_opensource
: 公共库,主要有各种
- lib_common
,各种ui组件,自定义组件,公用的
- base
、公用的
- Activity
,和公用的
- Fragment
等等。依赖
- utils
库。
- lib_coremodel
: 妹子功能模块,可以在
- module_girls
和
- library
之间切换,自己可以是一个
- application
也可以成为别的
- app
一个组件模块。组件化编译时为app,反之为module。
- app的
: 新闻功能模块,可以在
- module_news
和
- library
之间切换,自己可以是一个
- application
也可以成为别的
- app
的一个组件模块。组件化编译时为app,反之为module。
- app
: 定制版本的app,组件化编译时
- app_universal
和
- module_girls
为app,所以不能把这两个作为module加进来编译,所以组件化编译时
- module_news
要依赖
- app_universal
库,反之就可以把
- lib_common
和
- module_girls
作为module加进来编译。
- module_news
: 定制版本的app,组件化编译时
- app_specific
和
- module_girls
为app,所以不能把这两个作为module加进来编译,所以组件化编译时
- module_news
要依赖
- app_specific
库,反之就可以把
- lib_common
和
- module_girls
作为module加进来编译。
- module_news
使用
来跳转
- ARouter
和获取
- Activity
,记得看之前别人的组件化结构文章,一直都在纠结
- Fragment
的获取问题,我想说的是有了
- Fragment
来获取
- ARouter
不是超级简单么?
- Fragment
我们在工程根目录下的
文件中加入一个
- gradle.properties
类型的变量,通过修改这个变量来识别编译模式:
- Boolean
- # 每次更改“isModule”的值后,需要点击 "Sync Project" 按钮
- # isModule是“集成开发模式”和“组件开发模式”的切换开关
- isModule=false
然后在
和
- module_girls
中的
- module_news
文件中支持切换:
- build.gradle
- if (isModule.toBoolean()) {
- //组件化编译时为application
- apply plugin: 'com.android.application'
- } else {
- //非组件化编译时为library
- apply plugin: 'com.android.library'
- }
- android {
- compileSdkVersion build_versions.target_sdk
- buildToolsVersion build_versions.build_tools
- defaultConfig {
- minSdkVersion build_versions.min_sdk
- targetSdkVersion build_versions.target_sdk
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- //ARouter
- javaCompileOptions {
- annotationProcessorOptions {
- arguments = [moduleName: project.getName()]
- }
- }
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
- dataBinding {
- enabled = true
- }
- lintOptions {
- abortOnError false
- }
- sourceSets {
- main {
- if (isModule.toBoolean()) {
- //组件化编译时为app,在对应的AndroidManifest文件中需要写ndroid.intent.action.MAIN入口Activity
- manifest.srcFile 'src/main/module/AndroidManifest.xml'
- } else {
- manifest.srcFile 'src/main/AndroidManifest.xml'
- //集成开发模式下排除debug文件夹中的所有Java文件
- java {
- //debug文件夹中放的是Application类,非组件化时不用有此类
- exclude 'debug/**'
- }
- }
- }
- }
- }
- dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- api project(':lib_coremodel')
- api project(':lib_common')
- implementation 'com.android.support:support-v4:26.1.0'
- annotationProcessor deps.arouter.compiler
- }
上面看到了组件化和非组件化编译会有不用的
文件,组件化时需要
- AndroidManifest
文件夹下面的
- debug
类,非组件化时排除此文件夹。 6-组件化非组件化编译切换
- application
下的
- module
文件是组件化app编译时的,写了
- AndroidManifest
入口
- MAIN
- Activity
下是组件化app编译时的
- dubug
类,初始化作为一个
- Application
运行时需要的资源等等。在非组件化编译在
- app
文件中排除
- build.gradle
文件夹的所以东西。
- debug
后面会有一些列介绍在
组件化过程中使用
- MVVM
来跳转
- ARouter
和获取
- Activity
、
- Fragment
实现数据和UI的互相绑定、
- DataBinding
和
- Rxjava2
动态数据获取,和
- Retrofit2
的封装。
- AndroidViewModel
下面贴贴一个
库中我封装的
- lib_coremodel
,用泛型来确定数据类型,并且是动态URL获取数据:
- AndroidViewModel
- package google.architecture.coremodel.viewmodel;
- import android.app.Application;
- import android.arch.lifecycle.AndroidViewModel;
- import android.arch.lifecycle.LiveData;
- import android.arch.lifecycle.MutableLiveData;
- import android.databinding.ObservableField;
- import android.support.annotation.NonNull;
- import java.io.IOException;
- import java.lang.reflect.ParameterizedType;
- import google.architecture.coremodel.datamodel.http.ApiClient;
- import google.architecture.coremodel.datamodel.http.ApiConstants;
- import google.architecture.coremodel.datamodel.http.service.DynamicApiService;
- import google.architecture.coremodel.util.JsonUtil;
- import io.reactivex.Observer;
- import io.reactivex.android.schedulers.AndroidSchedulers;
- import io.reactivex.disposables.CompositeDisposable;
- import io.reactivex.disposables.Disposable;
- import io.reactivex.schedulers.Schedulers;
- import okhttp3.ResponseBody;
- /**
- * Created by dxx on 2017/11/20.
- */
- public class BaseViewModel < T > extends AndroidViewModel {
- //生命周期观察的数据
- private MutableLiveData < T > liveObservableData = new MutableLiveData < >();
- //UI使用可观察的数据 ObservableField是一个包装类
- public ObservableField < T > uiObservableData = new ObservableField < >();
- private final CompositeDisposable mDisposable = new CompositeDisposable();
- private static final MutableLiveData ABSENT = new MutableLiveData(); {
- //noinspection unchecked
- ABSENT.setValue(null);
- }
- public BaseViewModel(@NonNull Application application, String fullUrl) {
- super(application);
- ApiClient.initService(ApiConstants.GankHost, DynamicApiService.class).getDynamicData(fullUrl).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer < ResponseBody > () {@Override public void onSubscribe(Disposable d) {
- mDisposable.add(d);
- }
- @Override public void onNext(ResponseBody value) {
- if (null != value) {
- try {
- liveObservableData.setValue(JsonUtil.Str2JsonBean(value.string(), getTClass()));
- } catch(IOException e) {
- e.printStackTrace();
- }
- }
- }
- @Override public void onError(Throwable e) {
- }
- @Override public void onComplete() {
- }
- });
- }
- /**
- * LiveData支持了lifecycle生命周期检测
- * @return
- */
- public LiveData < T > getLiveObservableData() {
- return liveObservableData;
- }
- /**
- * 当主动改变数据时重新设置被观察的数据
- * @param product
- */
- public void setUiObservableData(T product) {
- this.uiObservableData.set(product);
- }
- public Class < T > getTClass() {
- Class < T > tClass = (Class < T > )((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
- return tClass;
- }
- @Override protected void onCleared() {
- super.onCleared();
- mDisposable.clear();
- }
- }
Demo的Github地址: github.com/Dawish/Goog…
来源: https://juejin.im/entry/5a193c696fb9a045204beae7