web-dev-qa-db-ja.com

ルーム内のIDでアイテムを取得する

AndroidプロジェクトでRoom + LiveDataを使用しています。 Googleブループリントに従って、アプリケーションのデータレイヤーを実装しました。

これは私のDaoがどのように見えるかです:

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

私は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
    }

NetworkManagerクラスは(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!!
    }
}

そして、ViewModelでLiveDataを取得することを期待した後:

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)
    }

}

問題。イベントのリストを同じ方法で取得しています(動作します!)上で説明しましたが、単一のイベント(これはイベントは既にデータベースにあります)動作しません。 localSource.valueがnull(NetworkManager)であることを発見しました。たぶん私のクエリが悪いか..何か他の。

8
P. Savrov

DAOの実装をもう一度確認してください。引数は、関数パラメーターと注釈引数の両方で同じでなければなりません。

これを変える:

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

に:

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