Android -room persistent library – DAO calls are async, therefore how to get callback?-ThrowExceptions

Exception or error:

From what i have read Room doesn’t allow you to issue database queries on the main thread (as can cause delays on the main thread)). so imagine i am trying to update a textview on the UI main thread which some data how would i get a call back. Let me show you an example. Imagine i want to store my business model data into a object called Events. We would therefore have a EventDao object:

imagine we have this DAO object below:

@Dao
public interface EventDao {

   @Query("SELECT * FROM " + Event.TABLE_NAME + " WHERE " + Event.DATE_FIELD + " > :minDate" limit 1)
   LiveData<List<Event>> getEvent(LocalDateTime minDate);

   @Insert(onConflict = REPLACE)
   void addEvent(Event event);

   @Delete
   void deleteEvent(Event event);

   @Update(onConflict = REPLACE)
   void updateEvent(Event event);

}

and now in some activity i have a textview and i’d like to update its value so i do this:

 myTextView.setText(EventDao.getEvent(someDate));/*i think this is illegal as im trying to call room dao on mainthread, therefore how is this done correctly ? would i need to show a spinner while it updates ?*/

since the fetching is occuring off of the main thread i dont think i can call it like this and expect a smooth update. Whats the best approach here ?

Some more information: i wanted to use the room database as mechanism for retrieving model information instead of keeping it statically in memory. so the model would be available to me locally through the db after i download it through a rest service.

UPDATE: so since i am returning a livedata then i can do this:

eventDao = eventDatabase.eventDao();
eventDao.getEvent().observe(this, event -> {
     myTextView.setText(event.get(0));
});

and that works for something very small. but imagine my database has a million items. then when i do this call, there will be a delay retrieving the data. The very first time this gets called it will be visible to the user that there is a delay. How to avoid this ? So to be clear , there are times i do not want live data, i just need to update once the view. I need to know how to do this ? even if its not with liveData.

How to solve:

If you want to do your query synchronously and not receive notifications of updates on the dataset, just don’t wrap you return value in a LiveData object. Check out the sample code from Google.

Take a look at loadProductSync() here

###

There is a way to turn off async and allow synchronous access.

when building the database you can use :allowMainThreadQueries()

and for in memory use: Room.inMemoryDatabaseBuilder()

Although its not recommended. So in the end i can use a in memory database and main thread access if i wanted super fast access. i guess it depends how big my data is and in this case is very small.

but if you did want to use a callback…. using rxJava here is one i made for a list of countries i wanted to store in a database:

public Observable<CountryModel> queryCountryInfoFor(final String isoCode) {
    return Observable.fromCallable(new Callable<CountryModel>() {
        @Override
        public CountryModel call() throws Exception {
            return db.countriesDao().getCountry(isoCode);
        }
    }).subscribeOn(Schedulers.io())

 .observeOn(AndroidSchedulers.mainThread());

}

you can then easily add a subscriber to this function to get the callback with Rxjava.

###

As Bohsen suggested use livedata for query synchronously. But in some special case, we want to do some asynchronous operation based on logic.
In below example case, I need to fetch some child comments for the parent comments. It is already available in DB, but need to fetch based on its parent_id in recyclerview adapter. To do this I used return concept of AsyncTask to get back the result. (Return in Kotlin)

Repositor Class

fun getChildDiscussions(parentId: Int): List<DiscussionEntity>? {
        return GetChildDiscussionAsyncTask(discussionDao).execute(parentId).get()
    }

private class GetChildDiscussionAsyncTask constructor(private val discussionDao: DiscussionDao?): AsyncTask<Int, Void, List<DiscussionEntity>?>() {
        override fun doInBackground(vararg params: Int?): List<DiscussionEntity>? {
            return discussionDao?.getChildDiscussionList(params[0]!!)
        }
    }

Dao Class

@Query("SELECT * FROM discussion_table WHERE parent_id = :parentId")
fun getChildDiscussionList(parentId: Int): List<DiscussionEntity>?

Leave a Reply

Your email address will not be published. Required fields are marked *