我正在尝试Room
数据库。 我不想观察我的数据,我只想一次从数据库中获取数据。如何使用MVVM实现此目标?
我面临的问题:如果我尝试在没有AsyncTask
的情况下获取数据,它将给出:无法访问主线程上的数据库,因为它可能会长时间锁定UI(如预期的那样),并且如果我使用AsyncTask
,则该方法返回null List
,因为在AsyncTask
完成之前该方法将返回。
道课:
@Query("SELECT * FROM student_table where StudentName = :studentName")List<Student> getStudentWithSameName(String studentName);
存储库:
public List<Student> getAllStudentWithSameName(String studentName) {
new GetAllStudentWithSameNameAsyncTask(studentDao).execute(studentName);
return studentsWithSameName;
}
private class GetAllStudentWithSameNameAsyncTask extends AsyncTask< String,Void, List<Student> > {
StudentDao studentDao;
public GetAllStudentWithSameNameAsyncTask(StudentDao studentDao) {
this.studentDao = studentDao;
}
@Override
protected List<Student> doInBackground(String... strings) {
List<Student> students = studentDao.getStudentWithSameName(strings[0]);
return students;
}
@Override
protected void onPostExecute(List<Student> students) {
studentsWithSameName = students;
super.onPostExecute(students);
}
}
ViewModel:
public List<Student> getStudentWithSameName(String studentName) {
studentsWithSameName = studentRepository.getAllStudentWithSameName(studentName);
return studentsWithSameName;
}
MainActivity:
viewModel = ViewModelProviders.of(this).get(StudentViewModel.class);
List<Student> students = viewModel.getStudentWithSameName("Bill");
class WordViewModel(application: Application) : AndroidViewModel(application) {
private var parentJob = Job()
private val coroutineContext: CoroutineContext
get() = parentJob + Dispatchers.Main
private val scope = CoroutineScope(coroutineContext)
private val repository: WordRepository
val allWords: LiveData<List<Word>>
init {
val wordsDao = WordRoomDatabase.getDatabase(application).wordDao()
repository = WordRepository(wordsDao)
allWords = repository.allWords
}
fun insert(word: Word) = scope.launch(Dispatchers.IO) {
repository.insert(word)
}
override fun onCleared() {
super.onCleared()
parentJob.cancel()
}
}
IMHO:比AsyncTask
好。您可以跟随Google的
codelabs
并学习如何使用Kotlin Coroutines
。
在我的YourClassDao.kt
中:
// this returns a LiveData object
@Query("SELECT * FROM my_table WHERE my_field = :myId")
fun getMyObject(myId: String): LiveData<List<YourClass>>
成为:
// this returns a normal object @Query("SELECT * FROM my_table WHERE my_field = :myId") suspend fun getMyObject(myId: String): List<YourClass>
就我而言,我像这样使用函数:
// using the second (suspend fun) version from above fun useMyData() { val database = AppDatabase.getInstance(context).YourClassDao() // context could be an activity, for example. val getDataJob = GlobalScope.async { database.getMyObject("someId") } getDataJob.invokeOnCompletion { cause -> if (cause != null) { //something happened and the job didn't finish successfully. Handle that here Unit } else { val myData = getDataJob.getCompleted() // ITEM 1 // *************************** // do something with your data // *************************** Unit // this is just because the lambda here has to return Unit } } // ITEM 2 }
请记住,这仍然适用于异步数据,因此我代码中的
ITEM 2
可能在ITEM 1
之前发生。