1

I have a simple app with a SearchView that users can query and depending on the state I'm showing/hiding some view widgets. I'm having trouble finding out why the ProgressBar is never visible. Can someone say why the loading indicator is never showing up?

Here is the code:

trait MainView {

  def searchIntent(): Observable[String]

  def render(viewState: PartialMainViewState)
}

Presenter:

class MainPresenter(...) {

  def bind(mainView: MainView) = {
    val searchQueryObservable = mainView.searchIntent()
      .flatMap(s => mainInteractor.search(s))

    searchQueryObservable.observeOn(AndroidSchedulers.mainThread()).subscribe { state => mainView.render(state) }
  }
}

The Activity with the actual rendering:

class SimpleActivity extends BaseSearchActivity with MainView {

  override def searchIntent(): Observable[String] = {
    Observable.defer {
      RxSearchView.queryTextChanges(vh.searchView)
        .filter((ev: CharSequence) => ev.length >= 2 || ev.length == 0)
        .debounce(500.milliseconds)
        .map[String]((ev: CharSequence) => ev.toString())
    }
  }

  override def render(viewState: PartialMainViewState): Unit =
    viewState match {
     case SearchNotStartedYet => renderSearchNotStarted()
     case Loading => renderLoading()
     case EmptyResult(_) => renderEmptyResult()
     case SearchResult(_, res) => renderResult(res)
     ...
    }

  def renderSearchNotStarted(): Unit = {
    vh.list.setVisibility(View.GONE)
    vh.progressBar.setVisibility(View.GONE)
    vh.emptyView.setVisibility(View.GONE)
  }

  def renderLoading(): Unit = {
    vh.list.setVisibility(View.GONE)
    vh.progressBar.setVisibility(View.VISIBLE)
    vh.emptyView.setVisibility(View.GONE)
  }

  def renderEmptyResult(): Unit = {
    vh.list.setVisibility(View.GONE)
    vh.progressBar.setVisibility(View.GONE)
    vh.emptyView.setVisibility(View.VISIBLE)
  }

  def renderResult(result: Array[String]): Unit = {
    vh.list.setVisibility(View.VISIBLE)
    vh.progressBar.setVisibility(View.GONE)
    vh.emptyView.setVisibility(View.GONE)
    //setting the adapter etc
  }

}

Here I'm simulating a network request:

class SimpleInteractor(...) {
  def search(query: String): Observable[PartialMainViewState] = {
    Thread.sleep(1500) // to simulate "Network latency"

    if(query.isEmpty) Observable.just(SearchNotStartedYet)

    else Observable.just(persons.filter(_.toLowerCase().contains(query.toLowerCase())))
      .map(array => {
        if(array.isEmpty) EmptyResult(query) else SearchResult(query, array)
      }).+:(Loading).onErrorReturn(error => ErrorState(query, error))
  }
}
user3350744
  • 449
  • 1
  • 5
  • 12

1 Answers1

1

In your presenter, try subscribing on different thread by adding subscribeOn operator:

searchQueryObservable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe { state => mainView.render(state) }
y.allam
  • 1,446
  • 13
  • 24
  • That makes the app crash with an `java.lang.IllegalStateException: Expected to be called on the main thread but was RxIoScheduler-2` – user3350744 Mar 26 '18 at 13:42
  • aha, i think this is because the source is a UI event. How about moving just the search part to `io` thread: `.flatMap(s => mainInteractor.search(s).subscribeOn(Schedulers.io()))` ? – y.allam Mar 26 '18 at 14:00
  • 1
    Debug the line `Thread.sleep(1500)` and see which thread you're suspending, my guess is that you're suspending the Main Thread, and that's why the progress bar doesn't appear – y.allam Mar 26 '18 at 14:03