I am experimenting with Room
database. I don't want my data to be observed, I just want to fetch data from the database once. How to achieve this using MVVM?
The problem I faced: If I try to fetch data without AsyncTask
it gives:
Can not access database on the main thread since it may potentially lock the UI for a long period of time(As expected) and if I use AsyncTask
, the method returns null List
as method returns before AsyncTask
is complete.
Dao class:
@Query("SELECT * FROM student_table where StudentName = :studentName")List<Student> getStudentWithSameName(String studentName);
Repository:
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");
You'll need to use an asynchronous ("suspend") function since a database call could potentially take a long time. Then to use the result, you'll have to invoke a block of code on completion instead of running it right away.
In my YourClassDao.kt
change fun
to suspend fun
, and LiveData<List<YourClass>>
to just List<YourClass>
:
// original: this returns a LiveData object
@Query("SELECT * FROM my_table WHERE my_field = :myId")
fun getMyObject(myId: String): LiveData<List<YourClass>>
becomes:
// new: this returns a normal object
@Query("SELECT * FROM my_table WHERE my_field = :myId")
suspend fun getMyObject(myId: String): List<YourClass>
To use the data, you'll need to start an asyncrnous job to get the data, and then invokeOnCompletion
the code you need to use the data.
// using the second (suspend fun) version from above
fun useMyData() {
val database = AppDatabase.getInstance(context).YourClassDao() // context could be an activity, for example.
// start an async job to get the data
val getDataJob = GlobalScope.async { database.getMyObject("someId") }
// tell the job to invoke this code when it's done
getDataJob.invokeOnCompletion { cause ->
if (cause != null) {
// error! 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 - this might happen before ITEM 1
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With