Get item by id in Room
25,236
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>
Author by
P. Savrov
Updated on October 06, 2020Comments
-
P. Savrov over 3 years
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.