RxJava2, как обновить существующую подписку при изменении параметра запроса - PullRequest
0 голосов
/ 07 октября 2018

У меня есть действие, для которого я делаю сетевой запрос каждый раз, когда изменяется пользовательский ввод.

Определение API выглядит следующим образом:

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

Так что это создает новый одноразовый доступ каждый раз, когда изменяется вход.Это явно неверно.Что я хочу сделать, это обновить существующую подписку с результатами нового сетевого вызова.

1 Ответ

0 голосов
/ 07 октября 2018

Прежде всего, вы думаете правильно, создание Observable для каждого события изменения далеко не эффективно.

Существует два подхода к этому:

Один

Вы можете использовать RxBinding , чтобы получить изменение текста Observable, теперь вы можете flatMap изменить текст вашего вызова apiService, вплоть до одного доступного.

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, см. Разницу в Здесь

...