【问题标题】:UI blocking occurs in Android despite RxJava尽管有 RxJava,但在 Android 中仍会发生 UI 阻塞
【发布时间】:2014-11-09 07:30:57
【问题描述】:

我正在使用 RxJava 将网络访问转移到 Android 中的单独线程,但我的 UI 仍然阻塞。

我没有使用错误的 observable,如下所示:Android RxJava, Non Blocking?

以下代码中的代码点 [A]、[B] 和 [C] 以 [A] -> [C] -> [B] 的顺序传递,因此当前线程处理良好,RxJava 调用 [C]一旦有了结果。这很好。

此外,与在 UI 线程上进行网络调用相比,阻塞要好得多,但我仍然有轻微阻塞。调用后 UI 保持流畅,但如果服务器在几毫秒内没有响应,则会阻塞。

    private search; // search is an instance variable in the same class

    // [A]

    Observable.just(search.find("something")) // search.find calls the REST endpoint
            .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Action1<Search>() {

                @Override public void call(Search search) {
                    // further processing // [B]
                }

            }, new Action1<Throwable>() {

                @Override public void call(Throwable throwable) {
                    // error handler
                }

            });

    // [C]

search 是 Observable 使用它的同一个类中的一个实例变量,但端点调用是从一个单独的库执行的,这可能是一个问题吗?应该没关系吧?

我有没有做不该做的坏事?

--

Find 看起来像这样(为简洁起见,删除了异常处理):

public Search find(String searchtext) {
    setSearchtext(searchtext);
    SearchEndpoint.find(Session.getUser().getId(), searchtext);
    return this;
}

这样的搜索端点:

public static Search find(final Long userId, final String searchtext) throws IOException {
    return ApiService.api().searches().find(userId).setFind(searchtext).execute();
}

并调用生成的 Google 云端点库。

【问题讨论】:

  • 您能否发布有关您的 search.find 方法的更多信息?我想它的返回类型是 Search 并且它是一个简单的同步方法调用?在这种情况下,just() 将调用 search.find(),阻塞直到它返回一个值,然后将这个值包装在一个 observable 中,它会立即调用 onNext 和 onCompleted。相反:要么使用 RetroFit,要么查看 Observable.create 以正确地将您的 REST 调用包装在 Observable 中......如果您需要更多帮助,请再次询问!

标签: android rx-java


【解决方案1】:

我知道这已经有几个月的历史了——但您可以使用 map 运算符来运行搜索,而不是 create 一个全新的 Observable(这相对容易出错):

String search_input = "something"; // this is where you can specify other search terms
Observable.just(search_input) 
      .map(s -> search.find(s))  // search.find calls the REST endpoint
      .subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe( // your subscriber goes here

如果不使用 lambda,map 函数应该如下所示:

.map(new Func1<String, Search>() {
      @Override          
      public Search call(String s) {
          return search.find(s)
      }
 })

【讨论】:

    【解决方案2】:

    试试这个:

    Observable.create(new Observable.OnSubscribe<Search>() {
    
        @Override
        // method signature is from memory - I hope I am correct...
        public void call(Subscriber<? super Search> subscriber) {
            try {
                Search search = search.find("something");
                subscriber.onNext(search);
                subscriber.onCompleted();
            } catch (SomeException e) {
                subscriber.onError(e);
            }
        }
    })
    // and then continue with your .subscribeOn(...)
    

    澄清一下,也许这会使您的代码问题更加明显:

    Observable.just(search.find("something"))
    

    显然等价于

    Search search = search.find("something");
    Observable.just(search)
    

    这很明显,search.find 在我们将控制权交给 rxjava 之前就已执行,它会在您当前所在的任何线程上执行 - 然后根据预先计算的值和交付构造一个 Observable的价值发生在另一个线程上,但这对你没有多大帮助......

    【讨论】:

    • 我昨天开始使用 RxJava,并认为 RxJava 会使用反射执行(只是)后面的任何内容。如果不是这种情况,那么您的解释是完全有道理的。有趣的是,它有点帮助。 [我现在不能测试,但我会稍后再给你反馈。]
    • 您重新定义变量搜索是否有原因?搜索 search = search.find("something"); -> IDE 告诉我“(搜索)可能尚未定义”。如果我去 search = search.find("something");代码编译正常。
    猜你喜欢
    • 2013-05-31
    • 2017-05-08
    • 1970-01-01
    • 2011-04-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多