Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get item by id in Room

Tags:

I'm using Room + LiveData in my Android project. Following to Google Blueprints, I've implemented data layer of my application.

This is how my Dao looks like:

@Query("SELECT * FROM events WHERE id=:arg0")
    fun loadSingle(id: String): LiveData<Event>

I'm calling it from my EventRepository:

fun loadSingle(eventId: String): LiveData<RequestReader<Event>> {
        return object: NetworkManager<Event, Event>(appExecutors!!) {

            override fun loadLocal(): LiveData<Event> {
                val item = eventLocal!!.loadSingle("Title 1")
                Crashlytics.log(Log.VERBOSE, TAG, "loadFromServer::loadLocal=$item")
                return item
            }

            override fun isUpdateForced(data: Event?): Boolean {
                Crashlytics.log(Log.VERBOSE, TAG, "loadFromServer::isUpdateForced")
                return data == null || requestTimeout.isAllowed(UNDEFINED_KEY.toString())
            }

            override fun makeRequest(): LiveData<ApiResponse<Event>> {
                Crashlytics.log(Log.VERBOSE, TAG, "loadFromServer::makeRequest")
                return Database.createService(EventRemote::class.java).load(eventId)
            }

            override fun onSuccess(item: Event) {
                eventLocal?.save(item)
            }

            override fun onFail() {
                Crashlytics.log(Log.VERBOSE, TAG, "loadFromServer::onFail")
                requestTimeout.reset(UNDEFINED_KEY.toString())
            }

        }.liveData
    }

Where NetworkManager class is (has been "taken" from here):

    abstract class NetworkManager<ResultType, RequestType> @MainThread constructor(val appExecutors: AppExecutors) {

        companion object {
            private val TAG = "TAG_NETWORK_MANAGER"
        }

        val liveData: MediatorLiveData<RequestReader<ResultType>> = MediatorLiveData()

        init {
            liveData.value = RequestReader.loading(null)
            val localSource: LiveData<ResultType> = loadLocal()
            Log.d(TAG, "before add::localSource=${localSource.value}")
            liveData.addSource(localSource, { data ->
                Log.d(TAG, "data=$data")
                liveData.removeSource(localSource)
                if (isUpdateForced(data)) {
                    loadRemote(localSource)
                } else {
                    liveData.addSource(localSource, { reusedData -> liveData.value = RequestReader.success(reusedData)})
                }
            })
        }

        private fun loadRemote(localSource: LiveData<ResultType>) {
            val remoteSource = makeRequest()
            liveData.addSource(localSource, {
                liveData.value = RequestReader.success(it)
            })
            liveData.addSource(remoteSource) { response ->
                liveData.removeSource(localSource)
                liveData.removeSource(remoteSource)
                if (response!!.isSuccessful) {
                    appExecutors.diskIO.execute {
                        onSuccess(processResponse(response))
                        appExecutors.mainThread.execute {
                            liveData.addSource(localSource, {
                                liveData.value = RequestReader.success(it)
                            })
                        }
                    }
                } else {
                    onFail()
                    liveData.addSource(localSource, {
                        liveData.value = RequestReader.error("Error: ${response.errorMessage}", it)
                    })
                }
            }

        }

        @MainThread
        protected abstract fun loadLocal(): LiveData<ResultType>

        @MainThread
        protected abstract fun isUpdateForced(data: ResultType?): Boolean

        @MainThread
        protected abstract fun makeRequest(): LiveData<ApiResponse<RequestType>>

        @WorkerThread
        protected abstract fun onSuccess(item: RequestType)

        @MainThread
        protected abstract fun onFail()

        @WorkerThread
        protected fun processResponse(response: ApiResponse<RequestType>): RequestType {
        return response.body!!
    }
}

And after i expect to get my LiveData in ViewModel:

open class EventSingleViewModel: ViewModel(), RepositoryComponent.Injectable {

    companion object {
        private val TAG = "TAG_EVENT_SINGLE_VIEW_MODEL"
    }

    @Inject lateinit var eventRepository: EventRepository

    var eventSingle: LiveData<RequestReader<Event>>? = null

    override fun inject(repositoryComponent: RepositoryComponent) {
        repositoryComponent.inject(this)
        eventSingle = MutableLiveData<RequestReader<Event>>()
    }

    fun load(eventId: String) {
        Crashlytics.log(Log.VERBOSE, TAG, "starts to loadList::eventId=$eventId")
        eventSingle = eventRepository.loadSingle(eventId)
    }

}

The problem. I'm getting a list of events the same way (it works!) I've described above, but with a single event (this event is already in database) it doesn't work. I've found out that localSource.value is null (in NetworkManager). Maybe my query is bad or.. something else.

like image 360
P. Savrov Avatar asked Oct 25 '17 14:10

P. Savrov


People also ask

What is Dao in room?

android.arch.persistence.room.Dao. Marks the class as a Data Access Object. Data Access Objects are the main classes where you define your database interactions. They can include a variety of query methods. The class marked with @Dao should either be an interface or an abstract class.

How do you read a room database?

Database Inspector Officially Support in Android Studio You have to choose your connected device, then need to choose package name that you want to inspect for database. In the left side, show the available tables and need to double click to see table details, and it will be show in the right side.


1 Answers

Check again your DAO implementation, the argument must be the same in both, the function parameter and the annotation arg.

Change this:

@Query("SELECT * FROM events WHERE id=:arg0")
fun loadSingle(id: String): LiveData<Event>

To:

@Query("SELECT * FROM events WHERE id=:id ")
fun loadSingle(id: String): LiveData<Event>
like image 107
Fredy Mederos Avatar answered Oct 31 '22 12:10

Fredy Mederos