1.官方文档

  MVVM 官方文档:  https://developer.android.com/jetpack/docs/guide

  ViewModel 文档:  https://developer.android.com/topic/libraries/architecture/viewmodel

  ViewModel保存状态:    https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate

  LiveData 官方文档: https://developer.android.com/topic/libraries/architecture/livedata 

2.android mvvm 软件架构简介

2.1 架构图示

  

  其中数字的简单描述如下:

    1. View通过ViewModel获取数据对象展示,并成为它的观察者。
    2. ViewModel通过Model得到真正的数据对象,根据业务需求通过model修改数据
    3. Model 只负责数据的操作:查找、从服务器下载新数据、修改等操作。

2.2 View

  • 负责数据显示、用户交互,系统交互。android系统中的Fragment 、Activity。
  • 只通过ViewModel得到目标数据对象展示并成为它的观察观察者。数据对象存在LiveData<XX>中。
  • 不处理业务逻辑,不打开数据库,不通过网络请求数据等.

2.3 Model

  • 数据抽象,封装
  • 数据存储(文件、内存、服务器、本地数据库等)、数据提取
  • 为ViewModel返回真正的数据对象(LiveData<xxx>)

2.4 ViewModel

  • 负责为View(View(Fragment 或 Activity))准备数据
  • 处理业务逻辑,不直接处理数据。
  • 与模型进行通信,后者存储、网络请求数据等

2.5 LiveData

  • 负责关联view与viewModel

3.LiveData

  • LiveData 一系列类模板,负责关联view与viewModel,采用观察者模式、类里存放被观察的数据,它的子类如下。

    

  • 具有系统组件(activity,fragment,service)生命周期感知能力(无需手动),系统确保只会将更新通知给活跃的观察者。
  • 不支持非主线程更新
 -- ::54.688 -/com.example.frgmtvm E/AndroidRuntime: FATAL EXCEPTION: Timer-
Process: com.example.frgmtvm, PID:
java.lang.IllegalStateException: Cannot invoke setValue on a background thread
at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:)
at androidx.lifecycle.LiveData.setValue(LiveData.java:)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:)
at com.example.frgmtvm.ui.main.MainViewModel$test1$.run(MainViewModel.kt:)
at java.util.TimerThread.mainLoop(Timer.java:)
at java.util.TimerThread.run(Timer.java:)

4.ViewModel

  • 如果在Activity、Fragment中保存数据,容易引起3个问题:

    • 当它们被销毁后再次重新构建的时候,需要重新请求加载数据,造成资源的浪费,
    • 如果请求数据是异步的,在销毁Activity时,容易引起内存泄漏。
    • Activity、Fragmen代码膨胀、不易维护、测试。
  • android中 ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。让数据可在发生屏幕旋转等配置更改后继续留存在.
  • 绝不能引用视图、Lifecycle 或可能存储对 Activity 上下文的引用的任何类
  • ViewModel 对象应该比它们相应 View 对象存在的时间更长,因此 ViewModel 实现中不得包含对 View 对象的直接引用。
  • 如果 ViewModel 需要 Application 上下文(例如,为了查找系统服务),可以扩展 AndroidViewModel 类
  • ViewModel 对象存在的时间范围是获取 ViewModel 时传递给 ViewModelProvider 的 ViewModelStoreOwner。ViewModel 将一直留在内存中,直到限定其存在时间范围的 ViewModelStoreOwner 永久消失:对于 Activity,是在 Activity finish时;而对于 Fragment,是在 Fragment  detach时。
  • SavedStateHandle 用来保存轻量的页面状态(key-value),可以把它们传给VIewModel 使用。

5.示例代码

完整代码:

  https://github.com/f9q/mvvm

5.1 第1步:定义Model

  • User

     class User {
    var name = "TEST-"
    var age = override fun toString(): String {
    return "$name-$age"
    }
    }
  • UserModel, 数据对象用LiveData系列类保存

     class UserModel {
    
         var userData    =   MediatorLiveData<User>()
    
         init {
    val user = User()
    userData.value = user
    } fun userFromSql() : LiveData<User> {
    return userData
    }
    fun userFromServer() : LiveData<User>{
    return userData
    }
    fun userFromFile() : LiveData<User>{
    return userData
    }
    fun userFromCache() : LiveData<User>{
    return userData
    } fun modifyUser(age : Int,name : String){
    val user = userData.value
    user?.age = age
    user?.name = name userData.value = user
    } }

5.2 第2步:定义ViewModel  

定义ViewModel,保存model对象,并提供返回数据对象的方法

 class MainViewModel : ViewModel{

     var userModel   :   UserModel  = UserModel()

     fun loadUser() : LiveData<User>{
val ud = userModel.userFromServer()
return ud
}
override fun onCleared() {
super.onCleared()
Log.e("MainViewModel","onCleared")
cancelTask()
}
//...
}

5.3 第3步:关联View与ViewModel

在android中,Fragment、activity被当作View

 class Fragment1 : Fragment() {

     lateinit var nameKey    : TextView
lateinit var nameValue : EditText
lateinit var ageKey : TextView
lateinit var ageValue : TextView val viewModel : MainViewModel by lazy { initViewModel() } fun initViewModel() : MainViewModel{
// return ViewModelProvider(this).get(MainViewModel::class.java)
return ViewModelProvider(activity!!).get(MainViewModel::class.java)
} fun bindViewModel(){
viewModel.loadUser().observe(viewLifecycleOwner){user->
nameValue.setText(user.name)
ageValue.setText(user.age.toString())
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
val v = inflater.inflate(R.layout.view1, container, false)
initView(v)
return v
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bindViewModel()
}
//...
}

  其中:

  • 第11行,绑定view与viewModel时使用的ViewModelStoreOwner是Fragment,viewModel的生命期与Fragment关联,退出Fragment后,数据失效
  • 第12行,使用ViewModelStoreOwner 是 Activity,该viewModel的生命期长,退出Activity才失效,可用于多个fragment 共享数据。
  • 第16行,关联view与对应的数据,当数据变化时,这里会得到通知,然后刷新界面。

  

android MVVM(1)用LiveData关联VM 与 V的更多相关文章

  1. android MVVM(2)用数据绑定关联VM 与 V

    1.官方文档 https://developer.android.com/topic/libraries/data-binding/architecture 2.简介 数据绑定库 可与MVVM 架构组 ...

  2. Android MVVM框架RoboBinding初探

    RoboBinding是一个实现了数据绑定 Presentation Model(MVVM) 模式的Android开源框架.MVVM模式是MVC模式的重要更新,使得项目结构更加的优美,易于维护以及方便 ...

  3. 如何构建Android MVVM 应用框架

    概述 说到Android MVVM,相信大家都会想到Google 2015年推出的DataBinding框架.然而两者的概念是不一样的,不能混为一谈.MVVM是一种架构模式,而DataBinding是 ...

  4. (Android MVVM)使用Data Binding Library(2)

    复习 上一篇学到了如何在layout.xml文件中增加元素,实现数据绑定,本篇接着学习. 事件处理 在layout.xml上绑定事件有两种方法,各有千秋. 1.方法引用 2.监听绑定 1.使用方法引用 ...

  5. Android Jetpack组件 - ViewModel,LiveData使用以及原理

    本文涉及的源码版本如下: com.android.support:appcompat-v7:27.1.1 android.arch.lifecycle:extensions:1.1.1 android ...

  6. Android开发利器之Data Binding Compiler V2 —— 搭建Android MVVM完全体的基础

    原创声明: 该文章为原创文章,未经博主同意严禁转载. 前言: Android常用的架构有:MVC.MVP.MVVM,而MVVM是唯一一个官方提供支持组件的架构,我们可以通过Android lifecy ...

  7. android mvvm初探

    目前google的databinding library还处在rc版,其中编译器发挥了主要作用.目前也只是在android studio开发环境中支持. mvvm能够大大降低模块间的耦合度,在开发过程 ...

  8. Android MVVM小结

    一.概念 关于MVC.MVP与MVVM的概念就不介绍了,总之一句话,MVVM概念出现比MVP早,MVP比MVC早,作为程序员就应该去学习最新的技术不是?详细的概念介绍移步这里吧,https://www ...

  9. Android ToolBar自定义图标,关联DrawerLayout

    Android5.0出现了一个可以代替ActionBar的控件ToolBar,使用更加灵活,一般我们使用ToolBar来和DrawerLayout配合使用,官方提供了一个开关类ActionBarDra ...

随机推荐

  1. Python3,逻辑运算符

    优先级 ()>not>and>or 1.or 在python中,逻辑运算符or,x or y, 如果x为True则返回x,如果x为False返回y值.因为如果x为True那么or运算 ...

  2. 微信公众平台上如何上传excel表格?

    微信公众平台上如何上传excel表格?   我们都知道创建一个微信公众号,在公众号中发布一些文章是非常简单的,但公众号添加附件下载的功能却被限制,如今可以使用小程序“微附件”进行在公众号中添加附件. ...

  3. SpringCloud Sidecar 整合.Net WebApi

    在整合.Net的过程中遇到不少问题,一般网上的例子只是调用一个简单的NodeJS示例,并未有详细的介绍及采坑过程. 首先,我的项目结构是:Vue前端 + SpringCloud后端 + .Net的We ...

  4. Assembly.LoadFrom() 方法加载程序集,无法转换类型

    有些情况在开发一个C#框架的时候,要用到反射加载另外程序集,这是必然考虑的事情.这样做的好处就是多个工程同时作业的时候,可以互不干扰,替换DLL文件即可. Assembly.Load();这个方法只能 ...

  5. vs2017引用vue组件中文乱码

    原因:文件默认编码格式为ASNI编码,需要改成UTF-8编码 解决方案: ①用记事本打开component.js文件 ②另存文件,修改编码为UTF-8编码,保存

  6. Vue源码解析,keep-alive是如何实现缓存的?

    前言 在性能优化上,最常见的手段就是缓存.对需要经常访问的资源进行缓存,减少请求或者是初始化的过程,从而降低时间或内存的消耗.Vue 为我们提供了缓存组件 keep-alive,它可用于路由级别或组件 ...

  7. AVL树旋转

    什么是AVL树? AVL树是带有平衡条件的二叉查找树,一颗AVL树首先是二叉查收树(每个节点如果有左子树或右子树,那么左子树中数据小于该节点数据,右子树数据大于该节点数据),其次,AVL树必须满足平衡 ...

  8. ajax、反向ajax、jsonp详解

    ajax详解 什么是ajax 其实ajax已经属于老技术了,现在几乎没人不会用了,在这里主要是把底层的东西给大家分享一下,以备应对装逼的面试官. ajax即“Asynchronous Javascri ...

  9. 5. JsonFactory工厂而已,还蛮有料,这是我没想到的

    少年易学老难成,一寸光阴不可轻.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习.关注公众号[ ...

  10. CAS和锁的相关面试题

    CAS 锁 锁的四种状态和升级 锁的四种状态:无锁.偏向锁.轻量级锁和重量级锁 无锁 无锁就是没有真正意义上的上锁,所有的线程还是能访问并修改同一个资源,但是通过算法控制,实现同时只有一个线程修改成功 ...