MVVM框架的搭建(二)——项目搭建

介绍完背景以及初衷之后,我们开始搭建MVVM的框架,这一部分我们进行简单的搭建,了解MVVM架构的基本结构。

创建新项目

首先创建一个新的项目,在根目录下创建一个config.gradle如图

config.gradle用于配置项目中各种lib引用和版本号控制

/**
 * config.gradle用于配置项目中各种lib引用和版本号控制
 *
 * [module_*] 各module版本号及applicationId控制
 * 如需在各个module中升级更新版本号,请使用 module_[modulename]*的命名规则
 *
 * [project.ext.dependVersion] 中创建各个依赖库的版本号控制,需在类库名称后增加‘_version’
 *
 * [类库maven地址] 中创建各个类库的maven地址,同一类库需要引用多个类时,可以使用数组,要确保类库引用不重复
 *
 * [项目依赖列表] 中创建可以直接让module引用的依赖列表,以Deps结尾,原则上以类库功能分类,比如网络库,图片处理库
 * 尽量不要以类库本身的名字命名依赖列表
 *
 * 各个module中引用类库时尽量使用项目依赖列表中的项目,不要直接使用类库地址中的项目
 *
 * 需要添加新的类库时,先查询本列表和项目中是否已引用类似功能的类库,尽量不要添加重复功能的类库
 */
project.ext {
    compileSdkVersion = 27
    buildToolsVersion = '27.0.3'
    minSdkVersion = 16
    targetSdkVersion = 27

    //主app
    module_appApplicationId = 'yang.cehome.com.mvvmdemo'
    module_appVersionCode = 0001
    module_appVersionName = '1.0.0'
    module_appName = 'MVVM'

    //引用类库的版本号
    dependVersion = [
            kotlin_version : '1.2.51',
            support_version: '27.1.1'
    ]

    //*************************类库maven地址**************************
    kotlin_base = [kotlin_stdlib_jdk8: "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$dependVersion.kotlin_version"]
    supportLibs = [
            design      : "com.android.support:design:$dependVersion.support_version",
            appcompat_v7: "com.android.support:appcompat-v7:$dependVersion.support_version",
            constraint  : 'com.android.support.constraint:constraint-layout:1.1.3']
    //********************项目依赖列表**********************
    kotlinDeps = [kotlin_base.values()]
    supportDeps = [supportLibs.values()]
}

然后再build.gradle我们引用相应的library库

使用的时候需要注意的地方

依赖方法

AndroidStudio升级到3.0之后,gradle版本也随之升级到了3.0.0版本。 在这之后,大家可能注意依赖的方式发生了一些变化,在这里简单介绍一下

依赖方式

写在前面

现在MVC MVP MVVM框架的介绍很多,网上一搜一大堆就不着重介绍了。 之前用MVP重新写的框架,但是也遇到了很多不方便的地方,所以这次我们着重介绍MVVM框架 这里开始使用kotlin,并遵循google的App开发架构指南,才找到一种较好的构建MVVM应用程序的方式 首先:什么是MVVM? MVVM是Model-View-ViewModel的简写,是有别于MVC和MVP的另一种架构模式。 相比于MVP,MVVM没有多余的回调,利用Databinding框架就可以将ViewModel中的数据绑定到UI上,从而让开发者只需要更新ViewModel中的数据,就可以改变UI。

再来讲一下分别的作用 ● Model层:负责提供数据源给ViewModel,包含实体类,网络请求和本地存储等功能 ● ViewModel:将Model层提供的数据根据View层的需要进行处理,通过DataBinding绑定到相应的UI上 ● View:Activity、Fragment、layout.xml、Adapter、自定义View等等,负责将三者联系起来。

另一个好处就是可以做单元测试,纯的kotlin代码写着再舒服不过,而且可以保证数据的正确性。相比于run app需要十几秒或者几分钟、十几分钟,run 一次单元测试是以毫秒记的,效率是很可观的。

代码实现

首先我们创建一个类

/**
 * @author yangzc
 *  @data 2018/9/6 13:58
 *  @desc
 *
 */
class Onclick(val who: String, val count: Int)
以前我们写一个点击事件的代码大概
布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="yang.cehome.com.mvvmdemo.MainActivity">

    <Button
        android:id="@+id/bt_onclick"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="onclick"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_count"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="100dp"
        android:textSize="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>
在Activity当中是这么实现的
package yang.cehome.com.mvvmdemo

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val onclik = Onclick("my", 0)
        tv_count.text = "${onclik.who}点击了${onclik.count}次"
        bt_onclick.setOnClickListener(View.OnClickListener {
            onclik.count++
            tv_count.text = "${onclik.who}点击了${onclik.count}次"
        })
    }
}

就实现了我们平时经常写的一段点击事件并且显示的一段代码 然而 我们要用MVVM框架显然就不是这么写的了 首先我们看一下架构

根据我们的这个结构图 我们简单阐述一下 各个模块的作用

Model层:负责提供数据源给ViewModel,包含实体类,网络请求和本地存储等功能 ViewModel层:将Model层提供的数据根据View层的需要进行处理,通过DataBinding绑定到相应的UI上 View层:Activity、Fragment、layout.xml、Adapter、自定义View等等,负责将三者联系起来 简单的介绍了一下MVVM之后,创建项目之后,看一下结构

包结构

基础Demo

下面我们就根据我们之前说的简单写一个Demo 首先看一下包的结构 DataBindingUtil.setContentView 这个函数做了三步操作:

  • inflate操作,创建布局文件对应的view对像
  • setContentView操作,将view加入window
  • bind操作,创建ActivityXxxBinding 对像 bind操作最终调用了ActivityXxxBinding.bind(view, bindingComponent)操作,然后调用了: new ActivityXxxBinding(bindingComponent, view) 创建了ActivityXxxBinding 对像。 //启用数据绑定 dataBinding{ enabled = true } 我们看看布局文件 其实 我们可以看到在MVVM当中布局文件的作用有所加强,不仅仅是构造一个UI效果。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <!--需要的viewModel,通过mBinding.vm=mViewMode注入-->
        <variable
            name="vm"
            type="yang.cehome.com.mvvmdemo.viewmodel.OnclikViewModel" />
    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".view.MainActivity">


        <Button
            android:id="@+id/bt_onclick"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{()->vm.click()}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="来点一下试试" />

        <TextView
            android:id="@+id/tv_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="100dp"
            android:text="@{vm.info}"
            android:textSize="16sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="点了0次" />

    </android.support.constraint.ConstraintLayout>
</layout>

值得注意的几点:

1.最外层增加layout标签 2.增加了一个data标签 这个标签是我们的ViewModel通过绑定注入的 3.在每个控件上增加相应的方法 下面看看M层的代码 提供给ViewModel层的数据

package yang.cehome.com.mvvmdemo.model

/**
 * @author yangzc
 *  @data 2018/9/6 13:58
 *  @desc 数据源Model(MVVM 中的V),负责提供ViewModel中需要处理的数据
 *
 */
class Onclick(val who: String, var count: Int)

下面我们在看看ViewModel层 这里主要承担了数据处理功能 并负责提供给View层数据 ViewModel是用来存储和管理UI相关的数据。

package yang.cehome.com.mvvmdemo.viewmodel

import android.databinding.ObservableField
import yang.cehome.com.mvvmdemo.model.Onclick

/**
 * @author yangzc
 *  @data 2018/9/6 16:59
 *  @desc 处理数据V(MVVM 中的VM),负责提供View中需要处理的数据
 *
 */
class OnclikViewModel(val onlick: Onclick) {
    /******data******/
    val info = ObservableField<String>("\"${onlick.who}点击了${onlick.count}次\"")

    /******binding******/
    fun click() {
        onlick.count++
        info.set("\"${onlick.who}点击了${onlick.count}次\"")
    }

}

最后我们看看View层,也就是我们Activity和Fragment

package yang.cehome.com.mvvmdemo.view

import android.databinding.DataBindingUtil
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import yang.cehome.com.mvvmdemo.R
import yang.cehome.com.mvvmdemo.databinding.ActivityMainBinding
import yang.cehome.com.mvvmdemo.model.Onclick
import yang.cehome.com.mvvmdemo.viewmodel.OnclikViewModel

/**
 * MVVM 当中的一个V层 将三者联系起来
 */
class MainActivity : AppCompatActivity() {
    private lateinit var mBinding: ActivityMainBinding
    private lateinit var mViewMode: OnclikViewModel


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        /////model
        val onclick = Onclick("me", 0)
        ///ViewModel
        mViewMode = OnclikViewModel(onclick)
        ///binding
        mBinding.vm = mViewMode
    }
}

以上就是一个简单的MVVM的框架

实现效果

项目地址

https://github.com/yang0range/MVVM

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

android Universal Image Loader for Android 说明文档 (1)

All manipulations are held by the ImageLoader class. It is a singletone, so to ...

21780
来自专栏图像识别与深度学习

《Android》Lesson02-第1个Project,Log

205120
来自专栏Android先生

(新瓶旧酒)谷歌官方MVP项目学习--浅入源码

项目的目的是通过展示各种架构app的不同方式来帮助开发者解决架构问题。项目中通过不同的架构概念及方式实现了功能相同的app。你可以用示例来当做参考,或是干脆拿来...

13610
来自专栏学海无涯

Android开发之DownloadManager的使用

Android 开发中,经常有从服务器下载数据的需求出现,尤其是在线更新App的情形。其基本思路是根据本地的App版本号和服务器的版本号进行比较,如果服务器版本...

42670
来自专栏程序员的诗和远方

搭建安卓开发环境(Android Studio)

最近想用业余时间学习一下android,教程,书本上以eclipse+adt居多,实际搜索一下,现在android studio好评还是比较多的,而且是goo...

75670
来自专栏Android中高级开发

Android开发之漫漫长途 番外篇——内存泄漏分析与解决

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索...

9120
来自专栏Android机动车

用代码手把手教你使用MVVM

网上关于MVVM框架的搭建和使用的文章很少,大多提到MVVM框架,就是在介绍DataBinding的使用。对于MVVM中各模块之间如何划分,如何定义,又是如何配...

16320
来自专栏技术小黑屋

Android内存泄漏检测利器:LeakCanary

到这里你就可以检测到Activity的内容泄露了。其实现原理是设置Application的ActivityLifecycleCallbacks方法监控所有Act...

18320
来自专栏小鄧子的技术博客专栏

【译】Retrofit 2 - 如何从服务器下载文件

如果你在阅读本文前没有写过任何一行Retrofit请求代码,那么最好看一下前面几篇博客。对于很多Retrofit使用者来说:定义一个下载文件的请求与其他请求几乎...

24610
来自专栏Golang语言社区

mysql_stmt_prepare failed! error(1461)Can't create more than

1461错误, mysql_stmt_prepare failed! 今天现场咨询我们问如何处理1461错误。 mysql_stmt_prepare faile...

61080

扫码关注云+社区

领取腾讯云代金券