没有LiveData的房间

时间:2019-02-14 23:04:59

标签: android android-room android-livedata

我正在尝试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;
}

3 个答案:

答案 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返回列表。