初识Kotlin 之6__探究Jetpack第二篇__ ViewModel的使用

本文接上篇  初识Kotlin 之6__探究Jetpack ,为 Jetpack 知识第二篇

一  ViewModel

ViewModel可以算是Jetpack中最重要的组件之一。ViewModel的一个重要作用是帮助Activity分担一部分工作。

它是专门用于存放与界面相关的数据的。 也就是说, 只要是界面上能看得到的数据,它的相关变量都应该存放在ViewModel中, 而不是Activity中, 这样可以在一定程度上减少Activity中的逻辑。

1. ViewModel是有生命周期的, 并且与Activity 不同, 它可以保证在手机屏幕发生旋转的时候不会被重新创建。 只有当Activity退出的时候才会跟着Activity 一起销毁。

    ViewModel的生命周期如图所示

2.  ViewModel的基本用法

由于Jetpack中的组件通常是以AndroidX库 的形式发布的,但是如果要想使用ViewModel组件, 需要在app/build.gradle文件中添加如下依赖:

dependencies{

    // 添加使用 viewmodel 组件

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

}

通常来讲, 比较好的编程规范是给每一个Activity 和 Fragment都创建一个对应的ViewModel, 在本示例中,我们为MainActivity 创建一个对应的MainViewModel类, 让它继承自ViewModel.

package com.rd.viewmodel

import androidx.lifecycle.ViewModel


class MainViewModel : ViewModel() {
    var counter = 0
}

MainActivity 代码如下:

package com.rd.jetpack

import android.content.Context
import android.content.SharedPreferences
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.core.content.edit
import androidx.lifecycle.ViewModelProviders
import com.rd.viewmodel.MainViewModel
import com.rd.viewmodel.MainViewModelFactory
import com.rd.lifecycle.MyObserver
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    /**
     *  lateinit 表示 这个变量会被初始化,并且不会为null,但是在声明这里,我暂时还不知道什么时候会被初始化
     */
    lateinit var  viewModel : MainViewModel
    lateinit var sp: SharedPreferences
    val count_reserved = "count_reserved"
    

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        lifecycle.addObserver(MyObserver(lifecycle))

        sp = getPreferences(Context.MODE_PRIVATE)
        val countReserved = sp.getInt(count_reserved, 0)

        /**
         * 保存当前计数的写法
         */
        viewModel =  ViewModelProviders.of(this, MainViewModelFactory(countReserved)).get(MainViewModel::class.java)

        /** 不保存计数的写法
         * viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
         */
        // +1 按钮
        plusOneBtn.setOnClickListener{
            viewModel.counter++
            refreshCounter()
        }
        //清零 按钮
        clearBtn.setOnClickListener {
            viewModel.counter=0
            refreshCounter()
        }
        refreshCounter()
    }


    private fun refreshCounter(){
        infoText.text = viewModel.counter.toString()
    }

    override fun onPause() {
        super.onPause()
        sp.edit{putInt(count_reserved,viewModel.counter)}
    }
}

3.  要注意的是, 我们绝对不可以直接去创建ViewModel的实例, 而是一定要通过ViewModelProviders 来获取ViewModel的实例, 

具体语法规则如下: ViewModelProviders.of(Activity 或 Fragment 的实例).get(<ViewModel的实例>::class.java)

之所以要这么写, 是因为ViewModel有其独立的生命周期,并且其生命周期要长于Activity。   如果在onCreate()中创建ViewModel的实例, 那么每次onCreate() 执行的时候,ViewModel都会创建一个新的实例,  这样当手机屏幕发生旋转的时候, 就无法保留其中的数据了。

4. 向ViewModel传递参数

由于所有ViewModel的实例都是通过ViewModelProviders 来获取的,因此我们没有任何地方可以向ViewModel的构造函数中传递参数。

要解决这个问题, 需要借助ViewModelProvider.Factory来实现,

特别注意: ViewModelProvider 和 ViewModelProviders 是两个不同的类,切勿混淆!

见下图所示

    

现在,修改MainViewModel的代码,如下所示:

package com.rd.viewmodel

import androidx.lifecycle.ViewModel


//以下为保存计数 的写法
class MainViewModel(countReserved: Int) : ViewModel(){

    var counter = countReserved
}

如何向MainViewModel的构造函数传递数据? 新建一个MainViewModelFactory类,让它实现ViewModelProvider.Factory接口,

package com.rd.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider

class MainViewModelFactory(private  val countReserved: Int): ViewModelProvider.Factory{

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return MainViewModel(countReserved) as T

    }
}

可以看到,MainViewModelFactory的构造函数中接收了一个countReserved参数。 在create()方法中创建了MainViewModel的实例,并带上了参数。

具体实例请参见 JetpackDemo1_20210219 示例。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值