zoukankan      html  css  js  c++  java
  • android MVVM(1)用LiveData关联VM 与 V

    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)生命周期感知能力(无需手动),系统确保只会将更新通知给活跃的观察者。
    • 不支持非主线程更新
    1 2020-07-22 11:18:54.688 22609-22704/com.example.frgmtvm E/AndroidRuntime: FATAL EXCEPTION: Timer-0
    2     Process: com.example.frgmtvm, PID: 22609
    3     java.lang.IllegalStateException: Cannot invoke setValue on a background thread
    4         at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:462)
    5         at androidx.lifecycle.LiveData.setValue(LiveData.java:304)
    6         at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
    7         at com.example.frgmtvm.ui.main.MainViewModel$test1$1.run(MainViewModel.kt:28)
    8         at java.util.TimerThread.mainLoop(Timer.java:562)
    9         at java.util.TimerThread.run(Timer.java:512)

    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
      1 class User {
      2     var name    =   "TEST-"
      3     var age     =   0
      4 
      5     override fun toString(): String {
      6         return "$name-$age"
      7     }
      8 }
    • UserModel, 数据对象用LiveData系列类保存

       1 class UserModel {
       2 
       3     var userData    =   MediatorLiveData<User>()
       4     
       5     init {
       6         val user = User()
       7         userData.value = user
       8     }
       9 
      10     fun userFromSql() : LiveData<User> {
      11         return userData
      12     }
      13     fun userFromServer() : LiveData<User>{
      14         return userData
      15     }
      16     fun userFromFile() : LiveData<User>{
      17         return userData
      18     }
      19     fun userFromCache() : LiveData<User>{
      20         return userData
      21     }
      22 
      23     fun modifyUser(age : Int,name : String){
      24         val user = userData.value
      25         user?.age = age
      26         user?.name = name
      27 
      28         userData.value = user
      29     }
      30 
      31 
      32 }

    5.2 第2步:定义ViewModel  

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

     1 class MainViewModel : ViewModel{
     2 
     3     var userModel   :   UserModel  = UserModel()
     4 
     5     fun loadUser() : LiveData<User>{
     6         val ud = userModel.userFromServer()
     7         return ud
     8     }
     9     override fun onCleared() {
    10         super.onCleared()
    11         Log.e("MainViewModel","onCleared")
    12         cancelTask()
    13     }
    14     //...
    15 }

    5.3 第3步:关联View与ViewModel

    在android中,Fragment、activity被当作View

     1 class Fragment1 : Fragment() {
     2 
     3     lateinit var nameKey    : TextView
     4     lateinit var nameValue  : EditText
     5     lateinit var ageKey     : TextView
     6     lateinit var ageValue   : TextView
     7 
     8     val viewModel           : MainViewModel by lazy { initViewModel() }
     9 
    10     fun initViewModel() : MainViewModel{
    11 //        return ViewModelProvider(this).get(MainViewModel::class.java)
    12         return ViewModelProvider(activity!!).get(MainViewModel::class.java)
    13     }
    14 
    15     fun bindViewModel(){
    16         viewModel.loadUser().observe(viewLifecycleOwner){user->
    17             nameValue.setText(user.name)
    18             ageValue.setText(user.age.toString())
    19         }
    20     }
    21     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
    22                               savedInstanceState: Bundle?): View {
    23         val v = inflater.inflate(R.layout.view1, container, false)
    24         initView(v)
    25         return v
    26     }
    27     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    28         super.onViewCreated(view, savedInstanceState)
    29         bindViewModel()
    30     }
    31     //...
    32 }        

      其中:

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

      

  • 相关阅读:
    转一篇GCC相关的文章
    STM32 NVIC
    阻塞套接字返回EAGAIN
    ndk编译libpcap 1.7.4(最终解决方法)
    ndk编译libpcap 1.7.4
    C# 解析torrent文件
    NPOI 读取excel的时候,时间格式的处理
    asp.net webapi 获取报文体的问题
    .net core 2.0 报错:error NU1102: Unable to find package 。。。
    SQL SERVER获取信息的方法
  • 原文地址:https://www.cnblogs.com/mhbs/p/13359607.html
Copyright © 2011-2022 走看看