別のスレッド(IO thread)など)でokhttpを使用してURLにリクエストし、AndroidメインスレッドでResponse
を取得しますが、 Observable
の作成方法がわかりません。
最初に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を作成せず、各オブザーバーに対して新しいObservableを作成します
Deferオペレーターは、オブザーバーがそれにサブスクライブするまで待機し、その後、通常Observableファクトリー関数を使用してObservableを生成します。これは各サブスクライバーに対して新たに行われるため、各サブスクライバーは同じObservableにサブスクライブしていると考えるかもしれませんが、実際には各サブスクライバーは独自のシーケンスを取得します。
MarcinKoziń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);
}
}
});
_
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);
}
}
});
このようにして、登録解除とバックプレッシャーが処理されます。 Dan Lewによる素晴らしい投稿create()
およびdefer()
についてです。
Observable.create()
ルートに行きたい場合は、 このライブラリ のようになり、isUnsubscribed()
呼び出しがどこにでも散らばっています。そして、これはまだ背圧を処理しないと思います。
私はこの投稿が少し古いことを理解していますが、今これを行うための新しいより便利な方法があります
Observable.fromCallable {
client.newCall(Request.Builder().url("your url").build()).execute()
}
詳細: https://artemzin.com/blog/rxjava-defer-execution-of-function-via-fromcallable/
議論に遅れましたが、何らかの理由でコードが応答本文をストリーミングする必要がある場合、defer
またはfromCallable
はそれを行いません。代わりに、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
_
Single.just(...)
で、監視可能な型を作成しますdefer
を使用すると、try-with-resourcesスタイルを使用できます。eager
トグルをfalse
に設定して、ディスポーザをターミナルイベントの後、つまりサブスクリプションコンシューマが実行された後に呼び出されるようにします。eager
をfalse
に設定しないと、このラムダに入る前に応答が既に閉じられているため、コードは理由 'closed'でIOExceptionを発生させます。onError
ラムダは、例外を処理する必要があります。特に、IOException
を使用したtry/catchでは可能だったので、using
演算子ではもうキャッチできないdefer
。