0

让我们从一个基本示例开始,

假设我有以下代码块用于从存储库获取Auth Token

private fun getToken(): LiveData<TokenResponse> {
        return LiveDataReactiveStreams.fromPublisher(remoteSource.getAuthToken()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .map { token -> token }
        )
    }

我在ViewModel中收到LiveData结果

class HomeModel {

        private var tokenLiveDataSource: MediatorLiveData<TokenResponse> = MediatorLiveData()
        private var tokenLiveData: MutableLiveData<TokenResponse> = MutableLiveData()

        fun observeTokenLiveData(): LiveData<TokenResponse> {
            return tokenLiveData
        }

        fun getToken() {
            val source = repository.getToken()
            tokenLiveDataSource.addSource(source) {
                tokenLiveData.value = it
                tokenLiveDataSource.removeSource(source)
            }
        }
    }

在这一点上,一切都完美无缺。但是,当我想将 2 个请求合并在一起并为每个请求获取单独的LiveData时,问题就来了。假设我想在收到Token API的结果后调用Search API 。我的目标是为每个步骤获得 2次 LiveData事件更改。下面给出了演示我的要求的修改代码,

private fun getSearchResult(): LiveData<?> {
    return LiveDataReactiveStreams.fromPublisher(remoteSource.getAuthToken() // 1ST API CALL
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .map { token ->
                // NOTIFY THE 1ST API RESULT/RETURN LiveData<TokenResponse>
                token
            }
            .flatMap { token ->
                remoteSource.getSearchResult(token) // 2ND API CALL
            }
            .map { results ->
                // NOTIFY THE 2ND API RESULT/RETURN LiveData<SearchResult>
                results
            }

    )
}

如何从给定的示例中接收 2 LiveData?

class HomeModel {

            private var tokenLiveDataSource: MediatorLiveData<TokenResponse> = MediatorLiveData()
            private var tokenLiveData: MutableLiveData<TokenResponse> = MutableLiveData()

            private var searchLiveDataSource: MediatorLiveData<SearchResponse> = MediatorLiveData()
            private var searchLiveData: MutableLiveData<SearchResponse> = MutableLiveData()

            fun observeTokenLiveData(): LiveData<TokenResponse> {
                return tokenLiveData
            }

            fun observeSearchLiveData(): LiveData<SearchResponse> {
                return searchLiveData
            }

            fun getSearchResult() {
                // RECEIVE 2 LiveData HERE
            }
        }
4

1 回答 1

1

创建一个可以同时包含令牌和搜索结果的包装类

data class TokenAndSearchResult(
    val tokenResponse: TokenResponse,
    val searchResponse: SearchResponse
)

然后是存储库:

private fun getSearchResult(): LiveData<TokenAndSearchResult> {
    return LiveDataReactiveStreams.fromPublisher(remoteSource.getAuthToken()
            .subscribeOn(Schedulers.io())
            // .observeOn(AndroidSchedulers.mainThread()) probably won't be needed. LiveData is observed in the main thread anyway.
            .flatMap { token ->
                remoteSource.getSearchResult(token) // Flowable<SearchResult>
                    .map { result -> TokenAndSearchResult(token, result) } // Flowable<TokenAndSearchResult>
                    .startWith(TokenAndSearchResult(token, SearchResult()))) // Flowable<TokenAndSearchResult>
            } // Flowable<TokenAndSearchResult>

    )
}

结果LiveData<TokenAndSearchResult>将发出一个TokenAndSearchResult带有令牌的实例。这个初始实例将有一个空的搜索结果,SearchResult()如上面的代码示例所示。

一旦remoteSource.getSearchResult()返回,它将第二次发出非空SearchResult值。

ViewModel 可以将此结果映射LiveData到个人LiveData

class HomeModel {

    // Declaring "var LiveData" is usually an anti-pattern, because
    // LiveData shouldn't change but only the object wrapped by LiveData
    // should change.
    private val tokenLiveData = MediatorLiveData<TokenResponse>() 
    private val searchLiveData = MediatorLiveData<SearchResponse>()

    fun observeTokenLiveData(): LiveData<TokenResponse> {
        return tokenLiveData
    }

    fun observeSearchLiveData(): LiveData<SearchResponse> {
        return searchLiveData
    }

    fun getSearchResult() {
        val source = repository.getSearchResult()
        tokenLiveData.addSource(source) {
            tokenLiveData.value = it.tokenResponse
            tokenLiveData.removeSource(source)
        }
        searchLiveData.addSource(source) {
            searchLiveData.value = it.searchResponse
            searchLiveData.removeSource(source)
        }
    }
}

补充思想:

一旦应用程序完成身份验证过程并获得身份验证令牌,应用程序通常希望保留该身份验证令牌,并且在令牌过期之前不重复该身份验证过程。它还应该具有检测 401 或 403 身份验证错误并在刷新令牌后重试的逻辑。

于 2019-09-30T20:17:02.107 回答