Android官方MVVM框架实现组件化之整体结构

Android官方MVVM框架实现组件化之整体结构

 

(一)的Android官方MVVM框架实现组件化之整体结构
(二)的Android官方MVVM框架实现组件化之ARouter串联各模块

目前的项目结构图置顶:Demo的Github地址:https//github.com/Dawish/GoogleArchitectureDemo

0-演示项目MVVM组件化架构图


一,谷歌官方MVVM框架讲解

前面对比了MVC和MVP “两张图看懂Android开发中MVC与MVP的区别”,可以相对于MVC我们的MVP是有多优越,但是Android开发现在已经开始流行了MVVM,前不久google官方发布了MVVM的正式库官方的正式MVVM库主要包括下面四个:

1-正式MVVM库组件

 

只有其中ViewModel的英文MVVM结构中的一个组件,其他的三个都是辅助性质的。

lifecycles就是处理UI界面的生命周期,在26版本以后的支持库中,AppCompatActivity状语从句:SupportActivity中都实现了LifecycleOwner,内部已经对UI界面的生命周期做了处理了。

LiveData是一个抽象类,我们可以存放UI页面需要的数据,就是把数据包装在LiveData中了,我们可以观测LiveData中的数据变化,但是LiveData的英文跟UI的生命周期关联的,当UI页面销毁了,LiveData的数据变化回调是不会执行的。

Room 就是一个sqlite的数据持久化库,我们也可以使用别的ORM库。


二,MVVM架构优势

“两张图看懂的Android开发中MVC与MVP的区别”前面两张图真是了MVC和MVP的区别,我这里也来一张图看看MVVM:

2- MVVM架构

图产品看上ModelView的英文不会发生关系的,ViewModel是把视图和模型关联起来的加工厂:

3 - 视图模型工厂

MVVM优势总结:

  1. View状语从句:Model双向绑定,一方的改变都会影响另一方,开发者不用再去手动修改UI的数据。额,互相自动的。

  2. 不需要findViewById也不需要butterknife,拿到不需要具体的View去设置数据绑定监听器等等,都这些可以用DataBinding完成。是不是很舒服?

  3. View状语从句:Model的双向绑定的英文请立即获取iTunes生命周期检测的,不会担心页面销毁了还有回调发生,由这个lifeCycle完成。

  4. 像不会MVC一样导致Activity中代码量巨大,不会也。像MVP一样出现大量的View状语从句:Presenter接口。项目结构更加低耦合。

  5. 更低的耦合把各个模块分开开发,分开测试,可以分给不同的开发人员来完成。


三,MVVM组件化示例项目架构分析

下图是项目模块和工程之间的依赖关系:

 

4- MVVM组件化示例项目架构图

 

下图是工程Android Studio中的目录结构:

 

5-工程目录结构

3.1各模块和彼此之间的关系解释:

  • lib_opensource:第三方的build.gradle依赖,本项目主要有supportlifecycleroomfrescoretrofitokhttpRxJavaARouter这些。

  • lib_coremodel:存放MVVM中的ModelViewModel两个模块,就是数据的处理和数据与UI页面的绑定。依赖lib_opensource库。

  • lib_common:公共库,主要有各种base,各种ui组件,自定义组件,公用的Activity,公用的Fragment,和公用的utils等等。依赖lib_coremodel库。

  • module_girls:妹子功能模块,可以在libraryapplication之间切换,自己可以是一个app也可以成为别的app的一个组件模块。组件化编译时为app,反之为模块。

  • module_news:新闻功能模块,可以在libraryapplication之间切换,自己可以是一个app也可以成为别的app的一个组件模块。组件化编译时为app,反之为模块。

  • app_universal:定制版本的app,组件化编译时module_girlsmodule_news为app,所以不能把这两个作为模块加进来编译,所以组件化编译时app_universal要依赖lib_common库,反之就可以把module_girls和作作module_news模块加进来编译。

  • app_specific:定制版本的app,组件化编译时module_girlsmodule_news为app,所以不能把这两个作为模块加进来编译,所以组件化编译时app_specific要依赖lib_common库,反之就可以把module_girls和作作module_news模块加进来编译。

3.2 ARouter串联各个模块

使用ARouter来跳转Activity状语从句:电子杂志Fragment,记得看之前别人的组件化结构文章,都一直在纠结Fragment的问题电子杂志,想说我的英文的有了ARouter来电子杂志Fragment不是该等超级简单么?

ARouter典型应用

  • 从外部URL映射到内部页面,以及参数传递与解析
  • 跨模块页面跳转,模块间解耦
  • 拦截跳转过程,处理登陆,埋点等逻辑
  • 跨模块的API调用,通过控制反转来做组件解耦

3.3组件化编译和非组件化编译切换

在我们工程根目录下的gradle.properties文件中加入一个Boolean类型的变量,通过修改这个变量来识别编译模式:

<span style="color:#2f2f2f"><span style="color:#abb2bf"><code># 每次更改“isModule”的值后,需要点击 "Sync Project" 按钮
# isModule是“集成开发模式”和“组件开发模式”的切换开关
isModule=false
</code></span></span>

在然后module_girls状语从句:module_news中的build.gradle文件中请立即获取iTunes e月刊:

<span style="color:#2f2f2f"><span style="color:#abb2bf"><code>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
}

</code></span></span>

看到上面了组件化状语从句:非组件化编译会有不用的AndroidManifest文件,化组件时需要debug文件夹数下面的application类,非组件化时排除此文件夹。

6-组件化非组件化编译切换

 

  • module的下AndroidManifest文件的英文组件化的应用程序编译时的,了写MAIN入口Activity
  • dubug下是组件化的应用程序时compile-的Application类,作为初始化一个app运行时需要的资源等等。非在化组件在compile- build.gradle文件中排除debug文件夹数的所以东西。

3.4最后预告:

会有后面列一些介绍在MVVM组件化过程中使用ARouter来跳转Activity状语从句:电子杂志FragmentDataBinding实现数据和UI的互相绑定,Rxjava2状语从句:Retrofit2动态数据电子杂志,状语从句:AndroidViewModel的封装。

贴下面贴一个lib_coremodel库中我封装的AndroidViewModel,用泛型来确定数据类型,并且是动态URL获取数据:

<span style="color:#2f2f2f"><span style="color:#abb2bf"><code><span style="color:#c678dd">package</span> google.architecture.coremodel.viewmodel;

<span style="color:#c678dd">import</span> android.app.Application;
<span style="color:#c678dd">import</span> android.arch.lifecycle.AndroidViewModel;
<span style="color:#c678dd">import</span> android.arch.lifecycle.LiveData;
<span style="color:#c678dd">import</span> android.arch.lifecycle.MutableLiveData;
<span style="color:#c678dd">import</span> android.databinding.ObservableField;
<span style="color:#c678dd">import</span> android.support.annotation.NonNull;

<span style="color:#c678dd">import</span> java.io.IOException;
<span style="color:#c678dd">import</span> java.lang.reflect.ParameterizedType;

<span style="color:#c678dd">import</span> google.architecture.coremodel.datamodel.http.ApiClient;
<span style="color:#c678dd">import</span> google.architecture.coremodel.datamodel.http.ApiConstants;
<span style="color:#c678dd">import</span> google.architecture.coremodel.datamodel.http.service.DynamicApiService;
<span style="color:#c678dd">import</span> google.architecture.coremodel.util.JsonUtil;
<span style="color:#c678dd">import</span> io.reactivex.Observer;
<span style="color:#c678dd">import</span> io.reactivex.android.schedulers.AndroidSchedulers;
<span style="color:#c678dd">import</span> io.reactivex.disposables.CompositeDisposable;
<span style="color:#c678dd">import</span> io.reactivex.disposables.Disposable;
<span style="color:#c678dd">import</span> io.reactivex.schedulers.Schedulers;
<span style="color:#c678dd">import</span> okhttp3.ResponseBody;

<span style="color:#929292">/**
 * Created by dxx on 2017/11/20.
 */</span>

<span style="color:#c678dd">public</span> <span style="color:#c678dd">class</span> <span style="color:#e6c07b">BaseViewModel</span><<span style="color:#e6c07b">T</span>> <span style="color:#c678dd">extends</span> <span style="color:#e6c07b">AndroidViewModel</span> {

    <span style="color:#929292">//生命周期观察的数据</span>
    <span style="color:#c678dd">private</span> MutableLiveData<T>  liveObservableData = <span style="color:#c678dd">new</span> MutableLiveData<>();
    <span style="color:#929292">//UI使用可观察的数据 ObservableField是一个包装类</span>
    <span style="color:#c678dd">public</span> ObservableField<T> uiObservableData = <span style="color:#c678dd">new</span> ObservableField<>();

    <span style="color:#c678dd">private</span> <span style="color:#c678dd">final</span> CompositeDisposable mDisposable = <span style="color:#c678dd">new</span> CompositeDisposable();

    <span style="color:#c678dd">private</span> <span style="color:#c678dd">static</span> <span style="color:#c678dd">final</span> MutableLiveData ABSENT = <span style="color:#c678dd">new</span> MutableLiveData();
    {
        <span style="color:#929292">//noinspection unchecked</span>
        ABSENT.setValue(<span style="color:#c678dd">null</span>);
    }


    <span style="color:#c678dd">public</span> <span style="color:#61aeee">BaseViewModel</span>(@NonNull Application application, String fullUrl) {
        <span style="color:#c678dd">super</span>(application);
        ApiClient.initService(ApiConstants.GankHost, DynamicApiService.class).getDynamicData(fullUrl).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread()).subscribe(<span style="color:#c678dd">new</span> Observer<ResponseBody>() {
            <span style="color:#61aeee">@Override</span>
            <span style="color:#c678dd">public</span> <span style="color:#c678dd">void</span> <span style="color:#61aeee">onSubscribe</span>(Disposable d) {
                mDisposable.add(d);
            }

            <span style="color:#61aeee">@Override</span>
            <span style="color:#c678dd">public</span> <span style="color:#c678dd">void</span> <span style="color:#61aeee">onNext</span>(ResponseBody value) {
               <span style="color:#c678dd">if</span>(<span style="color:#c678dd">null</span> != value){
                   <span style="color:#c678dd">try</span> {
                       liveObservableData.setValue(JsonUtil.Str2JsonBean(value.string(), getTClass()));
                   } <span style="color:#c678dd">catch</span> (IOException e) {
                       e.printStackTrace();
                   }
               }
            }

            <span style="color:#61aeee">@Override</span>
            <span style="color:#c678dd">public</span> <span style="color:#c678dd">void</span> <span style="color:#61aeee">onError</span>(Throwable e) {

            }

            <span style="color:#61aeee">@Override</span>
            <span style="color:#c678dd">public</span> <span style="color:#c678dd">void</span> <span style="color:#61aeee">onComplete</span>() {

            }
        });
    }

    <span style="color:#929292">/**
     * LiveData支持了lifecycle生命周期检测
     * <span style="color:#c678dd">@return</span>
     */</span>
    <span style="color:#c678dd">public</span> LiveData<T> <span style="color:#61aeee">getLiveObservableData</span>() {
        <span style="color:#c678dd">return</span> liveObservableData;
    }

    <span style="color:#929292">/**
     * 当主动改变数据时重新设置被观察的数据
     * <span style="color:#c678dd">@param</span> product
     */</span>
    <span style="color:#c678dd">public</span> <span style="color:#c678dd">void</span> <span style="color:#61aeee">setUiObservableData</span>(T product) {
        <span style="color:#c678dd">this</span>.uiObservableData.set(product);
    }

    <span style="color:#c678dd">public</span> Class<T> <span style="color:#61aeee">getTClass</span>(){
        Class<T> tClass = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[<span style="color:#d19a66">0</span>];
        <span style="color:#c678dd">return</span> tClass;
    }

    <span style="color:#61aeee">@Override</span>
    <span style="color:#c678dd">protected</span> <span style="color:#c678dd">void</span> <span style="color:#61aeee">onCleared</span>() {
        <span style="color:#c678dd">super</span>.onCleared();
        mDisposable.clear();
    }
}

</code></span></span>

Demo的Github地址:https//github.com/Dawish/GoogleArchitectureDemo

 

转载:https://www.jianshu.com/p/c0988e7f31fd

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值