android MVVM(2)用数据绑定关联VM 与 V ; viewModel 扩展包

1.官方文档

  https://developer.android.com/topic/libraries/data-binding/architecture

 

2.简介

  数据绑定库 可与MVVM 架构组件无缝协作。指定一下 binding的 lifecycleOwner 就可以了。如下:

 1 class PageFrgmt (var number : Int) : Fragment() {
 2 
 3     lateinit
 4     var binding     :   PageBinding
 5     val viewModel   :   DataViewModel by viewModels()
 6 
 7     fun initBinding(){
 8         binding.lifecycleOwner = this
 9         binding.number = number
10         binding.data = viewModel.data
11     }
12 
13     override fun onCreateView(
14         inflater: LayoutInflater,
15         container: ViewGroup?,
16         savedInstanceState: Bundle?
17     ): View? {
18         binding = PageBinding.inflate(inflater,container,false)
19         initBinding()
20         return binding.root
21     }
22 }

 

3.使用数据绑定与LiveData区别

使用数据绑定时,有两种方式实现数据更新通知 :

a. 使用  ObservableInt,ObservableFloat ... ObservableField<XX> 等

  • 缺点是这系列类不知道观察者(在mvvm架构中,通常是Activity,Fragment)的生命期变化,
  • 优点是不用在代码里写观察代码,如
    1        viewModel.loadUser().observe(viewLifecycleOwner){user->
    2             nameValue.setText(user.name)
    3             ageValue.setText(user.age.toString())
    4         }
  • 在android 3.1以上,可以直接把ObservableXXX 系列类,换成LiveData系列。

 

b. 使用 BaseObservable 基类,这时无法替换成LiveData

 

4.示例

4.1 定义Data与Model

Data:

 1 class Data : BaseObservable {
 2 
 3     constructor():super(){
 4         Log.e("MVVM_Data","constructor(), value = $value")
 5     }
 6     init{
 7         Log.e("MVVM_Data","init, value = $value")
 8         ++value
 9         name = "data$value"
10     }
11     @get:Bindable
12     var name    =   "unknown_"
13         set(value) {
14             field = value
15             notifyPropertyChanged(BR.name)
16         }
17 
18     companion object : BaseObservable(){
19         @get:Bindable
20         @JvmStatic var value   =   0
21             set(value) {
22                 field = value
23                 notifyPropertyChanged(BR.value)
24             }
25     }
26 }

Model

 1 class DataModel(var args : Bundle) {
 2 
 3     val liveData: MutableLiveData<Data> by lazy { initLiveData() }
 4     val data    :   Data  by lazy { initData() }
 5 
 6     fun initLiveData() : MutableLiveData<Data>{
 7         val data = Data().apply {
 8             name = "liveData"
 9         }
10         return MutableLiveData(data)
11     }
12 
13     fun initData() : Data{
14         return Data().apply {
15             name = "Data"
16         }
17     }
18 
19     fun loadData() : Data{
20         return data
21     }
22 
23     fun loadLiveData() : MutableLiveData<Data>{
24         return liveData
25     }
26 }

4.2 定义ViewModel

 1 class DataViewModel(var args : Bundle): ViewModel(),Observable {
 2 
 3     val model = DataModel(args)
 4 
 5     fun loadData() = model.loadData()
 6     fun loadLiveData() = model.loadLiveData()
 7 
 8     override fun onCleared() {
 9         super.onCleared()
10     }
11 
12     override fun removeOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) {
13     }
14 
15     override fun addOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) {
16     }
17 }

由于ViewModel有参数,默认的 ViewModelFactory不支持,需要自定义一个 ViewModelFactory

1 class DataViewModelFactory(var args : Bundle) : ViewModelProvider.Factory {
2 
3     override fun <T : ViewModel> create(modelClass: Class<T>): T {
4         if (modelClass.isAssignableFrom(DataViewModel::class.java)) {
5             return DataViewModel(args) as T
6         }
7         throw IllegalArgumentException("Unknown ViewModel class")
8     }
9 }

4.3 在View中用数据绑定关联View与ViewModel

 1 class PageFrgmt (var number : Int) : Fragment() {
 2 
 3     companion object {  @JvmStatic var  VMSOwner  =   false }
 4 
 5     lateinit
 6     var binding     :   PageBinding
 7 
 8     val viewModel1  :   DataViewModel by lazy { initViewModel() }
 9     val viewModel2  :   DataViewModel by activityViewModels(this::factory)
10     val viewModel3  :   DataViewModel by viewModels(this::ownerProducer,this::factory)
11 
12 
13     fun factory() : DataViewModelFactory{
14         return DataViewModelFactory(Bundle())
15     }
16     fun ownerProducer() : ViewModelStoreOwner {
17         return this
18     }
19 
20     fun initViewModel() : DataViewModel{
21         return if (VMSOwner){
22 //            ViewModelProvider(requireActivity()).get(DataViewModel::class.java)
23             ViewModelProvider(requireActivity(), DataViewModelFactory(Bundle())).get(DataViewModel::class.java)
24         }else{
25 //            ViewModelProvider(this).get(DataViewModel::class.java)
26             ViewModelProvider(this,DataViewModelFactory(Bundle())).get(DataViewModel::class.java)
27         }
28     }
29 
30     fun initBinding(){
31         binding.lifecycleOwner = this
32 //        val viewModel2  :   DataViewModel by activityViewModels(this::factory)
33 //        val viewModel3  :   DataViewModel by viewModels(this::ownerProducer,this::factory)
34         binding.data = if (VMSOwner) viewModel2.loadData() else viewModel3.loadData()
35     }
36 
37     override fun onCreateView(
38         inflater: LayoutInflater,
39         container: ViewGroup?,
40         savedInstanceState: Bundle?
41     ): View? {
42         Log.e("MVVM_TAG","PageFrgmt page $number onCreateView ,VMSOwner = $VMSOwner")
43         binding = PageBinding.inflate(inflater,container,false)
44         initBinding()
45         return binding.root
46     }
47 //...
48 }
  • 其中第8、9、10行:用3种方法定义了ViewModel成员
  • 第31行:指定了binding的生命期
  • 第34行:关联了view与ViewModel

绑定布局

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <layout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res-auto">
 4     <data>
 5         <variable name="data" type="com.example.mvvm2.model.Data" />
 6     </data>
 7     <androidx.constraintlayout.widget.ConstraintLayout
 8         android:background="#ffffff"
 9         android:layout_width="match_parent"
10         android:layout_height="match_parent">
11 
12         <TextView
13             ...
14             android:text="@{@string/data_format(data.name,data.value),default=@string/data_format}"
15            />
16 
17 
18     </androidx.constraintlayout.widget.ConstraintLayout>
19 </layout>

4.4 完整示例

  https://github.com/f9q/mvvm2 

 

5.ViewModel与application绑定

在指定ViewModel关联的生命期对象时,系统提供了activity和fragment,可以使用Application与ViewModel绑定。

5.1在application中定义 modelStoreOwner

1 class NxxApp : MultiDexApplication(), ViewModelStoreOwner {
2     val modelStoreOwner     =   ViewModelStore()
3     override fun getViewModelStore(): ViewModelStore {
4         return modelStoreOwner
5     }
6     //...
7 }    

5.2 关联ViewModel与Application

 1 class DeviceFrgmt : Fragment() {
 2     val viewModel      : DeviceViewModel   by lazy { initDeviceModel() }
 3     fun initDeviceModel() : DeviceViewModel{
 4         val app = activity?.application as NxxApp
 5         val vm = ViewModelProvider(app, DeviceViewModelFactory(app)).get(DeviceViewModel::class.java).apply {
 6             loadCallback    = this@DeviceFrgmt::loadDeviceCallback
 7             ...
 8         }
 9         return vm
10     }
11     fun initBinding(){
12         binding.lifecycleOwner = this
13         //...    
14     }
15 }

 

6. 扩展包

6.1 viewModels、activityViewModels

  4.3 节代码中的 activityViewModels 与 viewModels 可以简单构造viewModel ,它们所在包:

  implementation 'androidx.fragment:fragment-ktx:1.2.5'

6.2 ViewModelProvider 

 4.3 节代码中的  ViewModelProvider 所在包:

  implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

 

posted @ 2020-07-31 14:49  f9q  阅读(587)  评论(0编辑  收藏  举报