使用RxJava和Okhttp

时间:2015-09-21 05:27:17

标签: java android rx-java okhttp

我想在另一个线程(如IO线程)中使用okhttp请求一个url并在Android主线程中获取UIView* alertSubView = [alertView valueForKey:@"accessoryView"]; ,但我不知道如何创建Response

5 个答案:

答案 0 :(得分:25)

首先将RxAndroid添加到您的依赖项,然后像这样创建Observable

 Subscription subscription =   Observable.create(new Observable.OnSubscribe<Response>() {
        OkHttpClient client = new OkHttpClient();
          @Override
          public void call(Subscriber<? super Response> subscriber) {
            try {
              Response response = client.newCall(new Request.Builder().url("your url").build()).execute();
              if (response.isSuccessful()) {
                  if(!subscriber.isUnsubscribed()){
                     subscriber.onNext(response);
                  }
                  subscriber.onCompleted();
              } else if (!response.isSuccessful() && !subscriber.isUnsubscribed()) {
                  subscriber.onError(new Exception("error"));
                }
            } catch (IOException e) {
              if (!subscriber.isUnsubscribed()) {
                  subscriber.onError(e);
              }
            }
          }
        })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<Response>() {
              @Override
              public void onCompleted() {

              }

              @Override
              public void onError(Throwable e) {

              }

              @Override
              public void onNext(Response response) {

              }
            });

它会在另一个线程(io线程)中请求你的url并在android主线程上观察它。

最后当您离开屏幕时使用subsribtion.unsubscribe()以避免内存泄漏。

当你使用Observable.create时,你应该编写很多样板代码,你也必须自己处理订阅。更好的选择是使用defer。 形成文档:

  

在观察者订阅并创建之前不要创建Observable   为每个观察者提供一个新的观察者

     

Defer运算符等待观察者订阅它,然后   它生成一个Observable,通常带有一个Observable工厂   功能。它为每个用户重新做这件事,所以尽管每个用户都这样做   订阅者实际上可能认为它订阅了相同的Observable   每个订户都有自己独立的序列。

提到Marcin Koziński时,您只需要这样做:

final OkHttpClient client = new OkHttpClient();
Observable.defer(new Func0<Observable<Response>>() {
    @Override public Observable<Response> call() {
        try {
            Response response = client.newCall(new Request.Builder().url("your url").build()).execute();
            return Observable.just(response);
        } catch (IOException e) {
            return Observable.error(e);
        }
    }
});

答案 1 :(得分:18)

使用Observable.defer()代替Observable.create()更容易,更安全:

final OkHttpClient client = new OkHttpClient();
Observable.defer(new Func0<Observable<Response>>() {
    @Override public Observable<Response> call() {
        try {
            Response response = client.newCall(new Request.Builder().url("your url").build()).execute();
            return Observable.just(response);
        } catch (IOException e) {
            return Observable.error(e);
        }
    }
});

这样就可以为您处理取消订阅和背压。这里有this library create()defer()

如果您希望使用Observable.create()路线,那么它看起来应该更像https://api.github.com/users/octocat,其中isUnsubscribed()个电话随处可见。而且我相信这仍然无法处理背压。

答案 2 :(得分:10)

我意识到这篇文章有点陈旧,但现在有一种新的,更方便的方法

Observable.fromCallable {
        client.newCall(Request.Builder().url("your url").build()).execute()
    }

更多信息:https://artemzin.com/blog/rxjava-defer-execution-of-function-via-fromcallable/

答案 3 :(得分:0)

我来不及进行讨论,但是,如果由于某种原因代码需要流式传输响应主体,那么deferfromCallable就不会这样做。相反,可以使用using运算符。

Single.using(() -> okHttpClient.newCall(okRequest).execute(), // 1
             response -> { // 2
                 ...

                 return Single.just((Consumer<OutputStream>) fileOutput -> {
                     try (InputStream upstreamResponseStream = response.body().byteStream();
                          OutputStream fileOutput = responseBodyOutput) {
                         ByteStreams.copy(upstreamResponseStream, output);
                     }
                 });
             },
             Response::close, // 3
             false) // 4
      .subscribeOn(Schedulers.io()) // 5
      .subscribe(copier -> copier.accept(...), // 6
                 throwable -> ...); // 7
  1. 第一个lambda在订阅后执行
  2. 第二个lambda创建可观察的类型,此处为Single.just(...)
  3. 第三个lambda布置响应。使用defer可以使用try-with-resources样式。
  4. eager开关设置为false,以在终端事件之后(即在执行订阅使用者之后)调用该处置程序。
  5. 当然可以使事情发生在另一个线程池上
  6. 这是将消耗响应主体的lambda。如果没有将eager设置为false,则代码将引发IOException,原因为“ closed”,因为在输入此lambda之前,响应已经关闭。
  7. onError lambda应该处理异常,特别是IOException不能再捕获的using,因为使用defer进行try / catch可以实现。

答案 4 :(得分:0)

带有RxSingle后台API调用的Okhttp3。

     Disposable disposables = Single.fromCallable(() -> {
        Log.e(TAG, "clearData: Thread[" + Thread.currentThread().getName() + "]");
        OkHttpClient client = Util.getHttpClient();
        Request request = new Request.Builder()
                .addHeader("Authorization", "Bearer " + Util.getUserToken())
                .url(BuildConfig.BASE_URL + ApiConstants.DELETE_FEEDS)
                .build();

        Response response = client.newCall(request).execute();
        if(response.isSuccessful()) {
           ...
           return ; // Any  type
        } else {
           return ; // Any type        
        }
    }).subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe((result) -> {
           Log.d(TAG, "api() completed");
      });


    compositeDisposable.add(disposables);