Jetpack系列(四) — ViewModel

Jetpack系列(四) — ViewModel

ViewModel简单介绍

初步印象

在MVVM框架中ViewModel 负责逻辑判断,承接ViewRepository

ViewModel 生命周期存活在整个Activity生命周期,旋转不会重新创建

基本概念

ViewModelProviders 用户维护ViewModelStoreViewModelProvider.Factory关键方法public static ViewModelProvider of(Fragment fragment, Factory factory)

ViewModelStore 通过HashMap存储ViewModels

ViewModel基本使用

实现 ViewModel

  1. 创建ViewModel对象, 继承ViewModel

    // HomeViewModel.kt
    class HomeViewModel : ViewModel() {
    
        private var tapCount = 0
    
        private val _taps = MutableLiveData<String>("$tapCount taps")
    
        val taps: LiveData<String>
            get() = _taps
    
        fun updateTaps() {
            tapCount++
            _taps.postValue("$tapCount taps")
        }
    }
    复制代码
  2. 在View中间实例化ViewModel

    // HomeFragment.kt
    private val viewModel: HomeViewModel by viewModels()
    复制代码
  3. 通过LiveData观察ViewModel当中的数据变化

    //HomeViewModel.kt
    observe(viewModel.taps, ::tapsUpdate)   // LifecycleOwner 扩展函数
    
    private fun tapsUpdate(s: String?) {
        binding.tvCount.text = s ?: ""
    }
    复制代码

共享Fragment数据

  • 应用场景是在一个Fragment 中操纵数据,在另一个 Fragment用于显示该数据的内容。
  1. 创建ViewModel

    /**
     * ViewModel
     * 在 Fragment 之间共享数据
     */
    class MainViewModel : ViewModel() {
    
        private var _tapCount = 0
        private var _taps = MutableLiveData<String>("$_tapCount taps")
    
        val taps: LiveData<String>
            get() = _taps
    
        fun updateTaps() {
            _tapCount++
            _taps.value = "$_tapCount taps"
        }
    }
    复制代码
  2. HomeFragment中观察和操作数据

    // HomeFragment.kt
    class HomeFragment : Fragment() {
    
        private lateinit var binding: FragmentHomeBinding
    
        // 方式一: 通过viewModels() 创建ViewModel
        private val viewModel: HomeViewModel by viewModels()
        private val mainViewModel: MainViewModel by activityViewModels()
    
        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View {
            binding = FragmentHomeBinding.inflate(inflater, container, false)
            setHasOptionsMenu(true)
            return binding.root
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            ...
            initListener()
            subscribeUI()
        }
    
        private fun initListener() {
            binding.btnAdd.setOnClickListener { 
                mainViewModel.updateTaps()
            }
        }
    
        private fun subscribeUI() {
            // viewModel.taps.observe(viewLifecycleOwner, ::tapsUpdate)
            // 扩展函数
            observe(mainViewModel.taps, ::tapsUpdate) 
        }
    
        private fun tapsUpdate(s: String?) {
            binding.tvCount.text = s ?: ""
        }
     
    }
    复制代码
  3. DeepLinkFragment 当中观察数据

    class DeepLinkFragment : Fragment() {
    
        private lateinit var binding: FragmentDeepLinkBinding
        private val mainViewModel: MainViewModel by activityViewModels()
    
        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View {
            binding = FragmentDeepLinkBinding.inflate(inflater, container, false)
            return binding.root
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
    		...
            subscribeUI()
        }
    
        private fun subscribeUI() {
            observe(mainViewModel.taps, ::tapsUpdate)
        }
    
        private fun tapsUpdate(s: String) {
            binding.tap.text = s
        }
    }
    复制代码

相关知识点

知识点一:实例 ViewModel

  • 上述代码中直接使用viewModels()延时函数,将ViewModelViewModelStoreOwner自动绑定,然后直接使用ViewModel 实例

    // FragmentViewModelLazyKt.java
    @MainThread
    inline fun <reified VM : ViewModel> Fragment.viewModels(
        noinline ownerProducer: () -> ViewModelStoreOwner = { this },
        noinline factoryProducer: (() -> Factory)? = null
    ) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)
    
    @MainThread
    fun <VM : ViewModel> Fragment.createViewModelLazy(
        viewModelClass: KClass<VM>,
        storeProducer: () -> ViewModelStore,
        factoryProducer: (() -> Factory)? = null
    ): Lazy<VM> {
        val factoryPromise = factoryProducer ?: {
            defaultViewModelProviderFactory
        }
        return ViewModelLazy(viewModelClass, storeProducer, factoryPromise)
    }
    复制代码
  • viewModels() 可以传入参数, 手动创建XxxxViewModel

    //  SearchFragment.kt
    private val viewModel: SearchViewModel by viewModels { LiveDataVMFactory }
    
    object LiveDataVMFactory : ViewModelProvider.Factory {
    
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            @Suppress("UNCHECKED_CAST")
            return SearchViewModel(RepoRepository(GithubService.create())) as T
        }
    }
    复制代码
  • viewModels() 实际上做了两个动作,一是创建ViewModel实例,一是绑定ViewModel对象,等效于下述代码

    // 注: 代码来自《Android 第一行代码》
    // MainActivity.java 
    lateinit var viewModel: MainViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
     		...
        	// 绑定ViewModel对象
            viewModel = ViewModelProviders.of(this, MainViewModelFactory(countReserved)).get(MainViewModel::class.java)
            viewModel.counter.observe(this, Observer{ count ->
                infoText.text = count.toString()
            })
            viewModel.user.observe(this, Observer { user ->
                infoText.text = user.firstName
            })
            ...
        }
    
    // MainViewModelFactory.kt
    // 创建`ViewModel`实例
    class MainViewModelFactory(private val countReserved: Int) : ViewModelProvider.Factory {
    
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return MainViewModel(countReserved) as T
        }
    
    }
    复制代码

知识点二: ViewModel 生命周期

  • ViewModel将一直留在内存中,直到限定其存在时间范围的 Lifecycle永久消失:对于 Activity,是在 Activity 完成时;而对于 Fragment,是在 Fragment 分离时。

viewmodel-lifecycle.png

相关链接

Jetpack系列(一) — Navigation

Jetpack系列(二) — Lifecycle

Jetpack系列(三) — LiveData

参考资料

官网

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享