3

I'm converting our project to work with Room ORM. It works great when I need a LiveData object updated, and works great for AsyncTasks such as insert, delete, etc., where I do not need a callback. But I'm confused what to use when I need a one-time query that requires a callback. The options are to call AsyncTask to query using the DAO implementation, or LiveData with Observer, and after the first receive, unregister the observer.

galaxigirl
  • 2,390
  • 2
  • 20
  • 29

3 Answers3

1

I would recommend sticking with the LiveData, particularly if you are using a ViewModel provided by Room. The ArchitectureComponents library really does a great job when it comes to bundling all Room, LiveData and ViewModels together, so try at best to stick with the convention.

The reasons I recommend sticking with LiveData and ViewModels are

  1. ViewModels are Lifecycle aware, meaning they respond appropriately to Fragment/Activity state changes which would otherwise leave your AsyncTask either retrieving data for a dead Activity or doing work when the Activity is no longer there potentially leading to MemoryLeaks
  2. It's best practice (at least for Architecture Components) for a View to observe data/changes to data. If you need just a single callback, unsubscribe after you have received the data. Or use an RxJava single if you are currently using RxJava

If you feel the need to really want to use AsyncTask, I would suggest use an AsyncTaskLoader. This is a more robust/lifecycle aware background thread operation that will cache your data (it is very similar to an AsyncTask so the implementation details won't be too foreign), so if you rotate your device, the data will be cached and is immediately available, and you won't have a memory leak. Also check this Video on loaders by the Android team.

But I advise using the LiveData w/ ViewModels.

martinomburajr
  • 1,235
  • 14
  • 29
0

I had same issue with Room Implementation. As for LiveData return by room we can observe this on main thread without performing database operation on main thread. But for fetching Raw object without LiveData we can't do it directly, As database operations on Main thread are not allowed.

I have used LiveData for list of things which I what to keep updated as soon as Database gets Updated. But for some operations I need to fetch it only once and stop observing the database because I know it won't change.

In my case I have used RxJava to Observe the query result only 1 time

Creating Observable for getting User by id from Repository

Observable.create(object : ObservableOnSubscribe<User> {
        override fun subscribe(e: ObservableEmitter<User>) {
            val user= userRepo.getUserById(currentUserId)
            e.onNext(user)
            e.onComplete()
        }
    })
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(GetCurrentUserByIdSubscriber())

Repository

fun getUserById(id: Int): User= userDao.getUserById(id)

Dao

@Query("SELECT * FROM users WHERE id= :id")
fun getUserById(id: Int): User

You can see I am returning plain User object instead of LiveData.

In Activity where I want to observe this

private inner class GetCurrentUserByIdSubscriber : Observer<User> {
    override fun onSubscribe(d: Disposable) {}

    override fun onNext(t: User) {
        // update the view after getting the data from database
        user_name.text = t.name
    }

    override fun onComplete() {}

    override fun onError(e: Throwable) {}
}

So this is how I can perform one time database fetch on IO thread with RxJava and get callback as soon as object is fetched from the database. You can call unsubscribe on Subscription return from subscribe() method after results are obtained.

adityakamble49
  • 1,971
  • 18
  • 27
0

There is simple solution in Transformations method distinctUntilChanged.expose new data only if data was changed.

in case Event behaviour use this: https://stackoverflow.com/a/55212795/9381524

Jurij Pitulja
  • 5,546
  • 4
  • 19
  • 25