我有一个活动,每次用户输入发生变化时,我都会发出网络请求。
接口定义如下:
interface Api {
@GET("/accounts/check")
fun checkUsername(@Query("username") username: String): Observable<UsernameResponse>
}然后是管理所有内容的服务:
class ApiService {
var api: Api
init {
api = retrofit.create(Api::class.java)
}
companion object {
val baseUrl: String = "https://someapihost"
var rxAdapter: RxJava2CallAdapterFactory = RxJava2CallAdapterFactory.create()
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(rxAdapter)
.build()
}
fun checkUsername(username: String): Observable<UsernameResponse> {
return api.checkUsername(username)
}
}然后,在我的活动中,每当EditText内容发生变化时,我都会发出这个调用:
private fun checkUsername(username: String) {
cancelSubscription()
checkUsernameDisposable = ApiService()
.checkUsername(username)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
updateUi(it)
}
}因此,每次输入更改时,这都会创建一个新的一次性对象。这显然是不正确的。我想做的是用新网络调用的结果更新现有的订阅。
发布于 2018-10-07 07:14:11
首先,您的想法是正确的,为每个更改事件创建一个Observable的效率很低。
有两种方法可以解决这个问题:
One
您可以使用RxBinding来获取文本更改Observable,现在您可以将文本更改flatMap到您的apiService调用中,减少到一个disposable。
disposable = RxTextView.textChanges(editText)
.switchMap { ApiService().checkUsername(it) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { updateUi(it) }两个
您可以使用Subject作为EditText更改的通道,如下所示:
val editTextChangesSubject: PublishSubject<String> = PublishSubject.create()
// when the editText changes call
editTextChangesSubject.onNext(newText)
disposable = editTextChangesSubject
.switchMap { ApiService().checkUsername(it) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { updateUi(it) }现在也只剩下一个一次性的了!
注意:如果人们使用将视图逻辑与中间人逻辑分开的特定体系结构模式,则有时倾向于使用Subject技术,如果您不受此约束,则可以使用RxBinding。
此外,值得一提的是,这两种方法将为您提供订阅每个文本更改事件时所没有的功能,比如使用debounce或onBackpressureLatest等流控制操作符。
编辑
使用switchMap而不是flatMap,查看Here的区别
https://stackoverflow.com/questions/52684030
复制相似问题