我正在尝试Room
数据库。 我不想观察我的数据,我只想一次从数据库中获取数据。如何使用MVVM实现此目标?
我面临的问题:如果我尝试在没有AsyncTask
的情况下获取数据,它将给出:
无法访问主线程上的数据库,因为它可能长时间锁定UI(如预期的那样),并且如果我使用AsyncTask
,则该方法返回null List
,因为该方法在{{ 1}}完成。
道课:
AsyncTask
存储库:
@Query("SELECT * FROM student_table where StudentName = :studentName")List<Student> getStudentWithSameName(String studentName);
ViewModel:
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);
}
}
MainActivity:
public List<Student> getStudentWithSameName(String studentName) {
studentsWithSameName = studentRepository.getAllStudentWithSameName(studentName);
return studentsWithSameName;
}
答案 0 :(得分:2)
使用Kotlin:
要返回直接类型而不是LiveData,请更改您的YourClassDao.kt
文件以对该方法使用suspend
函数,然后将返回类型从LiveData<SOMETHING>
更改为{{1} }。 (您还需要更改任何调用该方法的函数,但这些函数很容易找到,因为在您修复它之前它不会编译。)由于它是a suspend function,因此您需要以不同的方式调用它
在我的SOMETHING
中:
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
。
答案 1 :(得分:0)
您可以将其用作example:
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()
}
}
恕我直言:它比
AsyncTask
更好。
您可以关注Google的codelabs
,并学习如何使用Kotlin Coroutines
。
答案 2 :(得分:0)
使用:
?
然后您的任务将等待结果。我还建议从asyncTask返回列表。