(一)Android官方MVVM框架实现组件化之整体结构
来源:互联网 发布:机器人聊天软件 编辑:程序博客网 时间:2024/05/18 02:48
作者: Dawish_大D
简书: http://www.jianshu.com/u/40e1f22c2c53(一)Android官方MVVM框架实现组件化之整体结构
(二)Android官方MVVM框架实现组件化之ARouter串联各模块
目前的项目结构图置顶:Demo的Github地址: https://github.com/Dawish/GoogleArchitectureDemo
一、google官方MVVM框架讲解
我前面对比了MVC和MVP《两张图看懂Android开发中MVC与MVP的区别》,可以相对于MVC
我们的MVP
是有多优越,但是Android开发现在已经开始流行了MVVM
,前不久google官方发布了MVVM的正式库。官方的正式MVVM库主要包括下面四个:
其中只有ViewModel
是MVVM结构中的一个组件,其他的三个都是辅助性质的。
lifecycles
就是处理UI界面的生命周期,在26版本以后的Support库中,AppCompatActivity
和SupportActivity
中都实现了LifecycleOwner
,内部已经对UI界面的生命周期做了处理了。
LiveData
是一个抽象类,我们可以存放UI页面需要的数据,就是把数据包装在LiveData
中了,我们可以观测LiveData
中的数据变化,但是LiveData
是跟UI的生命周期关联的,当UI页面销毁了,LiveData
的数据变化回调是不会执行的。
Room
就是一个sqlite数据持久化库,我们也可以使用别的ORM库。
二、MVVM架构优势
《两张图看懂Android开发中MVC与MVP的区别》 前面两张图真是了MVC和MVP的区别,我这里也来一张图看看MVVM:
看上图Model
和View
是不会发生关系的,ViewModel
是把View和Model关联起来的加工厂:
MVVM优势总结:
View
和Model
双向绑定,一方的改变都会影响另一方,开发者不用再去手动修改UI的数据。额,互相自动的。不需要
findViewById
也不需要butterknife
,不需要拿到具体的View
去设置数据绑定监听器等等,这些都可以用DataBinding
完成。是不是很舒服?View
和Model
的双向绑定是支持生命周期检测的,不会担心页面销毁了还有回调发生,这个由lifeCycle
完成。不会像
MVC
一样导致Activity
中代码量巨大,也不会像MVP
一样出现大量的View
和Presenter
接口。项目结构更加低耦合。更低的耦合把各个模块分开开发,分开测试,可以分给不同的开发人员来完成。
三、MVVM组件化示例项目架构分析
下图是项目模块和工程之间的依赖关系:
下图是工程Android Studio中的目录结构:
3.1 各模块和彼此之间的关系解释:
lib_opensource
:第三方build.gradle依赖,本项目主要有support
、lifecycle
、room
、fresco
、retrofit
、okhttp
、RxJava
、ARouter
这些。lib_coremodel
: 存放MVVM中的Model
和ViewModel
两个模块,就是数据的处理和数据与UI页面的绑定。依赖lib_opensource
库。lib_common
: 公共库,主要有各种base
,各种ui组件,自定义组件,公用的Activity
、公用的Fragment
,和公用的utils
等等。依赖lib_coremodel
库。module_girls
: 妹子功能模块,可以在library
和application
之间切换,自己可以是一个app
也可以成为别的app的
一个组件模块。组件化编译时为app,反之为module。module_news
: 新闻功能模块,可以在library
和application
之间切换,自己可以是一个app
也可以成为别的app
的一个组件模块。组件化编译时为app,反之为module。app_universal
: 定制版本的app,组件化编译时module_girls
和module_news
为app,所以不能把这两个作为module加进来编译,所以组件化编译时app_universal
要依赖lib_common
库,反之就可以把module_girls
和module_news
作为module加进来编译。app_specific
: 定制版本的app,组件化编译时module_girls
和module_news
为app,所以不能把这两个作为module加进来编译,所以组件化编译时app_specific
要依赖lib_common
库,反之就可以把module_girls
和module_news
作为module加进来编译。
3.2 ARouter串联各个模块
使用ARouter
来跳转Activity
和获取Fragment
,记得看之前别人的组件化结构文章,一直都在纠结Fragment
的获取问题,我想说的是有了ARouter
来获取Fragment
不是超级简单么?
ARouter典型应用
- 从外部URL映射到内部页面,以及参数传递与解析
- 跨模块页面跳转,模块间解耦
- 拦截跳转过程,处理登陆、埋点等逻辑
- 跨模块API调用,通过控制反转来做组件解耦
3.3 组件化编译和非组件化编译切换
我们在工程根目录下的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
文件夹下面的application
类,非组件化时排除此文件夹。
module
下的AndroidManifest
文件是组件化app编译时的,写了MAIN
入口Activity
dubug
下是组件化app编译时的Application
类,初始化作为一个app
运行时需要的资源等等。在非组件化编译在build.gradle
文件中排除debug
文件夹的所以东西。
3.4 最后预告:
后面会有一些列介绍在MVVM
组件化过程中使用ARouter
来跳转Activity
和获取Fragment
、DataBinding
实现数据和UI的互相绑定、Rxjava2
和Retrofit2
动态数据获取,和AndroidViewModel
的封装。
下面贴贴一个lib_coremodel
库中我封装的AndroidViewModel
,用泛型来确定数据类型,并且是动态URL获取数据:
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地址: https://github.com/Dawish/GoogleArchitectureDemo
- (一)Android官方MVVM框架实现组件化之整体结构
- (二)Android官方MVVM框架实现组件化之ARouter串联各模块
- 实现Android网络框架:(一)整体设计
- Android之MVVM框架 - 数据绑定
- 轻量级前端MVVM框架avalon - 整体架构
- 轻量级前端MVVM框架avalon:整体架构
- android-linux系统调用原理之整体系统框架实现原理之OPEN实现
- 【Android四大组件之Service】(一)Android中Service(服务)的官方介绍
- 前端MVVM框架设计及实现(一)
- android 快速开发框架,基于组件化的MVP结构
- Android 框架MVVM详解
- Android MVVM框架 DataBinding
- android之官方下拉刷新组件SwipeRefreshLayout
- android之官方下拉刷新组件SwipeRefreshLayout
- android之官方下拉刷新组件SwipeRefreshLayout
- android之官方下拉刷新组件SwipeRefreshLayout
- android之官方下拉刷新组件SwipeRefreshLayout
- android之官方下拉刷新组件SwipeRefreshLayout
- handler倒计时跳转页
- 剑指offer---替换空格(4)
- MR--Text
- 设计模式之外观模式(Facade)
- 数据结构实验之图论五:从起始点到目标点的最短步数(BFS)
- (一)Android官方MVVM框架实现组件化之整体结构
- 一个最简单的爬虫-url管理器
- 比CycleGAN更强的非监督GAN----DistanceGAN
- PL/sql Developer 卡死后 sql文件里的语句没了,如何找回原来的内容?
- LeetCode:ZigZag Conversion
- 一个最简单的爬虫-HTML下载器
- Ubuntu14.04安装caffe(cpu版)
- bzoj1034: [ZJOI2008]泡泡堂BNB
- jQuery Validation Plugin