我真的很喜欢RxJava,它是一个很棒的工具,但有时它很难理解它的工作原理。 我们在Android项目中使用Retrofit和RxJava,并且有以下用例:
我需要轮询服务器,重试之间有一些延迟,而服务器正在做一些工作。服务器完成后,我必须提供结果。所以我用RxJava成功完成了它,这里是代码片段: 我用过" skipWhile"用" repeatWhen"
Subscription checkJobSubscription = mDataManager.checkJob(prepareTweakJob)
.skipWhile(new Func1<CheckJobResponse, Boolean>() {
@Override
public Boolean call(CheckJobResponse checkJobResponse) {
boolean shouldSkip = false;
if (SHOW_LOGS) Logger.v(TAG, "checkJob, skipWhile, jobStatus " + checkJobResponse.getJobStatus());
switch (checkJobResponse.getJobStatus()){
case CheckJobResponse.PROCESSING:
shouldSkip = true;
break;
case CheckJobResponse.DONE:
case CheckJobResponse.ERROR:
shouldSkip = false;
break;
}
if (SHOW_LOGS) Logger.v(TAG, "checkJob, skipWhile, shouldSkip " + shouldSkip);
return shouldSkip;
}
})
.repeatWhen(new Func1<Observable<? extends Void>, Observable<?>>() {
@Override
public Observable<?> call(Observable<? extends Void> observable) {
if (SHOW_LOGS) Logger.v(TAG, "checkJob, repeatWhen " + observable);
return observable.delay(1, TimeUnit.SECONDS);
}
}).subscribe(new Subscriber<CheckJobResponse>(){
@Override
public void onNext(CheckJobResponse response) {
if (SHOW_LOGS) Logger.v(TAG, "checkJob, onSuccess, response " + response);
}
@Override
public void onError(BaseError error) {
if (SHOW_LOGS) Logger.v(TAG, "checkJob, onError, canEditTimeline, error " + error);
Toast.makeText(ChoseEditOptionActivity.this, R.string.NETWORK__no_internet_message, Toast.LENGTH_LONG).show();
}
@Override
public void onCompleted() {
if (SHOW_LOGS) Logger.v(TAG, "onCompleted");
}
});
代码工作正常:
当服务器响应该作业正在处理时,我返回&#34; true&#34;来自&#34; skipWhile&#34;链,原始的Observable等待1秒钟再次执行http请求。 这个过程一直重复,直到我返回&#34; false&#34;来自&#34; skipWhile&#34;链
以下是我不理解的一些事情:
我在&#34; skipWhile&#34;的文档中看到了它不会从原始的Observable发出任何东西(onError,onNext,onComplete),直到我返回&#34; false&#34;来自&#34;来电&#34;方法。因此,如果它没有发出任何东西,为什么&#34;重复当&#34;可观察到它的工作?它等待一秒钟并再次运行请求。是谁推出了它?
第二个问题是:为什么Observable来自&#34; repeatWhen&#34;我没有永远地跑,我的意思是为什么当我回来时它会停止重复&#34; false&#34;来自&#34; skipWhile&#34;?如果我返回&#34; false&#34;我在我的订阅者中成功登录。
在&#34; repeatWhile&#34;的文档中它说最终我打电话给&#34; onComplete&#34;在我的订阅者中,但是&#34; onComplete&#34;永远不会被召唤。
如果我改变链接的顺序没有区别&#34; skipWhile&#34;并且&#34;重复当&#34;。那是为什么?
我知道RxJava是开源的,我只能阅读代码,但正如我所说 - 它真的很难理解。
感谢。
答案 0 :(得分:14)
我之前没有和repeatWhen
合作,但这个问题让我很好奇,所以我做了一些研究。
skipWhile
确实会发出onError
和onCompleted
,即使它之前永远不会返回true
。因此,每次repeatWhen
发出checkJob()
时都会调用onCompleted
。这回答了问题#1。
其余问题是基于错误的假设。您的订阅永远在运行,因为您的repeatWhen
永远不会终止。那是因为repeatWhen
是比你意识到的更复杂的野兽。每当Observable
从源获取null
时,onCompleted
就会发出onCompleted
。如果您接受并返回delay
则结束,否则如果您发出任何内容则会重试。由于null
仅接受发射并延迟发射,因此它总是再次发出onCompleted
。因此,它不断重新订阅。
然后,#2的答案是它永远在运行;您可能正在执行此代码之外的其他操作来取消订阅。对于#3,你永远不会得到takeUntil
,因为它永远不会完成。对于#4,订单并不重要,因为您无限期地重复。
现在的问题是,你如何得到正确的行为?它就像使用skipWhile
而不是Observable<Boolean> source = ...; // Something that eventually emits true
source
.repeatWhen(completed -> completed.delay(1, TimeUnit.SECONDS))
.takeUntil(result -> result)
.filter(result -> result)
.subscribe(
res -> System.out.println("onNext(" + res + ")"),
err -> System.out.println("onError()"),
() -> System.out.println("onCompleted()")
);
一样简单。这样,您不断重复直到获得所需的结果,从而在您希望结束时终止该流。
这是一个代码示例:
source
在此示例中,true
正在发出布尔值。我每1秒重复一次,直到源发出result
。我一直在等true
false
。我会过滤掉true
的所有通知,因此订阅者在<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/bTextUrl"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:background="#faf6f6"
android:layout_marginTop="60dp"
android:nextFocusDown="@+id/bSendUrl">
<requestFocus></requestFocus>
</EditText>
<Button
android:layout_width="@dimen/latimea_button_send_tv"
android:layout_height="@dimen/inaltimea_button_send_tv"
android:text="@string/button_send_android_tv"
android:id="@+id/bSendUrl"
android:background="@drawable/button_send_tv"
android:layout_below="@+id/bTextUrl"
android:layout_alignParentStart="true"
android:layout_marginTop="35dp" />
</Button>
using (var client = new HttpClient(HttpClientHandlerFactory.GetWindowsAuthenticationHttpClientHandler()))
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string base64SerializedToken = "SuperDuperLongBase64String_IMeanSuperDuper";
client.DefaultRequestHeaders.Add("X-My-Custom-Header", base64SerializedToken);
Uri baseUri = new Uri("http:www.mywebapiservice.com");
Uri destinationUri = new Uri(baseUri, "doSomething");
HttpResponseMessage response = client.PostAsJsonAsync(new Uri(new Uri(this._baseUri), destinationUri.ToString()).ToString(), accountName).Result;
if (response.IsSuccessStatusCode)
{
returnItem = response.Content.ReadAsAsync<MyCustomReturnObject>().Result;
}
else
{
string errorMessage = response.Content.ReadAsStringAsync().Result;
throw new InvalidOperationException(errorMessage);
}
}
public static class HttpClientHandlerFactory
{
public static HttpClientHandler GetWindowsAuthenticationHttpClientHandler()
{
HttpClientHandler returnHandler = new HttpClientHandler()
{
UseDefaultCredentials = true,
PreAuthenticate = true
};
return returnHandler;
}
}
之前无法获取这些通知。