Android_Jetpack:Room与LiveData、ViewModel的结合使用

如果不使用LiveData自动获取数据的变化,那么当每次数据库中的数据发生变化时,我们都要开启一个工作线程去重新获取数据库中的数据。
比如说,在进入页面时,要获取数据库中全部学生信息列表,一般我们会这么写:

thread{
    studentList = studentDao.getStudentList() as MutableList<Student>
    runOnUiThread {
        arrayAdapter = ArrayAdapter(this,android.R.layout.simple_list_item_1,studentList)
        listView.adapter = arrayAdapter
    }
}

首先开个工作线程去获取数据库中存储的学生列表,然后再回到UI线程中进行界面更新。这样既不方便又有可能因为忘记开线程而造成的程序出错,但是,结合LiveData及ViewModel,就可以在数据发生变化时,通过LiveData组件通知View层,实现数据的自动更新。
要想实现这个功能,我们需要对程序做如下改动:
①修改学生表Dao文件。
这里我们希望当学生列表数据发生变化时,能够收到实时通知,因此,我们将getStudentList()方法的返回对象用LiveData包装起来。

package com.example.jetpacktest.room

import androidx.lifecycle.LiveData
import androidx.room.*

@Dao
interface StudentDao {
    @Insert
    fun insertStudent(student:Student)
    @Delete
    fun deleteStudent(student: Student)
    @Update
    fun updateStudent(student: Student)
    @Query("SELECT * FROM student")
    fun getStudentList():LiveData<List<Student>>
    @Query("SELECT * FROM student WHERE id = :id")
    fun getStudentById(id:Long):Student
}

②创建StudentViewModel类。
在StudentViewModel类中调用StudentDao里的getStudentList()方法。

package com.example.jetpacktest.room

import androidx.lifecycle.ViewModel

class StudentViewModel(studentDao: StudentDao) : ViewModel() {
    var studentLiveData = studentDao.getStudentList()
}

③创建StudentViewModelFactory类。
因为我们在StudentViewModel类中传递了StudentDao参数,因此我们需要有这么个类实现ViewModelProvider.Factory接口,以便于将StudentDao在实例化时传入。
以下写法为模板化写法,根据实际需求参数不同,做微调即可。

package com.example.jetpacktest.room

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

class StudentViewModelFactory(private val studentDao: StudentDao): ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return StudentViewModel(studentDao) as T
    }
}

④在Activity中实例化StudentViewModel,并监听LiveData的变化。

package com.example.jetpacktest.room

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.example.jetpacktest.AppDatabase
import com.example.jetpacktest.R
import kotlinx.android.synthetic.main.activity_room_test_main.*
import kotlin.concurrent.thread

class RoomTestMainActivity : AppCompatActivity() {
    private var studentList:MutableList<Student> = arrayListOf()
    private lateinit var arrayAdapter:ArrayAdapter<Student>
    lateinit var studentDao: StudentDao
    lateinit var viewModel: StudentViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_room_test_main)
        studentDao = AppDatabase.getDatabase(this).studentDao()
//        thread{
//            studentList = studentDao.getStudentList() as MutableList<Student>
//            runOnUiThread {
//                arrayAdapter = ArrayAdapter(this,android.R.layout.simple_list_item_1,studentList)
//                listView.adapter = arrayAdapter
//            }
//        }

		//Room与LiveData、ViewModel的结合使用,代替上面注释掉的部分
        arrayAdapter = ArrayAdapter(this,android.R.layout.simple_list_item_1,studentList)
        listView.adapter = arrayAdapter
        viewModel = ViewModelProvider(this,StudentViewModelFactory(studentDao)).get(StudentViewModel::class.java)
        viewModel.studentLiveData.observe(this, Observer { stList->
            studentList.clear()
            studentList.addAll(stList)
            arrayAdapter.notifyDataSetChanged()
        })
        ......
    }
}

运行程序,onChanged()方法会被自动调用,之后其他增删改操作都会在该方法内通知Adapter刷新数据,其他什么都不用做。
如:

fun addClick(view: View){
    if (nameEdt.text.toString() == "" || ageEdt.text.toString() == ""){
        Toast.makeText(this,"姓名或年龄不能为空",Toast.LENGTH_SHORT).show()
        return
    }
    val student = Student(nameEdt.text.toString(),ageEdt.text.toString().toInt())
    thread{
        studentDao.insertStudent(student)
    }
}

页面自动刷新。

Android_Jetpack:Room与LiveData、ViewModel的结合使用
Android_Jetpack:Room与LiveData、ViewModel的结合使用
Android_Jetpack:Room与LiveData、ViewModel的结合使用

上一篇:java – Manifest合并失败:属性应用程序@ appComponentFactory更新Firebase库


下一篇:android – 为什么butterknife 9.0.0-SNAPSHOT无法解析?