如果不使用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)
}
}
页面自动刷新。