为什么不调用doOnNext()?

时间:2017-04-29 03:18:19

标签: android rx-java rx-android reactivex

下面没有为我的订阅者调用onNext()和onCompleted()。我尝试通过doOnNext()/ doOnTerminate()实现订阅。我也试过doAfterTerminate()。我也试过明确定义订阅者,并且onNext()和onCompleted()都没有被调用。

根据RxJS reduce doesn't continue,它是不会终止的reduce()所以我尝试添加了take(1),但这并没有奏效。在同一个stackoverflow问题中有人说问题可能是我的流永远不会关闭。除了take(1)之外,也许我还有其他一些方法可以关闭流,但我还不太了解ReactiveX。

根据Why is OnComplete not called in this code? (RxAndroid),可能是系列中的原始流不会终止。但是我不明白为什么如果我打电话给take(1),我认为应该发出一个终止信号。

基本上,为什么不执行以下行?

System.out.println("doOnNext map.size()=" + map.size());

即使以下代码行执行了98次:

map.put(e.getKey(), e.getValue());

JsonObjectObservableRequest.java

import com.android.volley.toolbox.JsonObjectRequest;
...
public class JsonObjectObservableRequest {

    public JsonObjectObservableRequest(int method, String url, JSONObject request) {
    jsonObjectRequest = new JsonObjectRequest(method, url, request, getResponseListener(),     getResponseErrorListener());
    }

    private Response.Listener<JSONObject> getResponseListener() {
        return new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                publishSubject.onNext(Observable.just(response));
            }
        };
    }

    private Response.ErrorListener getResponseErrorListener() {
        return new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Observable<JSONObject> myError = Observable.error(error);
                publishSubject.onNext(myError);
            }
        };
    }

    public JsonObjectRequest getJsonObjectRequest() {
        return jsonObjectRequest;
    }

    public Observable<JSONObject> getObservable() {
    return publishSubject.flatMap(new Func1<Observable<JSONObject>, Observable<    JSONObject>>() {
            @Override
            public Observable<JSONObject> call(Observable<JSONObject> jsonObjectObservable) {
                return jsonObjectObservable;
            }
        });
    }
}

JsonObjectObservableRequest调用代码

import com.android.volley.Request;
import com.android.volley.RequestQueue;
...
    JsonObjectObservableRequest jsonObjectObservableRequest = new JsonObjectObservableRequest(Request.Method.GET, idURLString, null, keyId, key);
    Observable<JSONObject> jsonObjectObservable = jsonObjectObservableRequest.getObservable();

    jsonObjectObservable
            .map(json -> {
                try {
                    return NetworkAccountIdDatasource.parseIdJSON(json);
                } catch (JSONException e) {
                    e.printStackTrace();
                    return null;
                }
            })
            .flatMapIterable(x -> x)
            .map(s -> new AbstractMap.SimpleEntry<String, String>("Name of " + s, "short id for " + s.substring(4)))
            .reduce(new HashMap<String, String>(), (map, e) -> {
                map.put(e.getKey(), e.getValue());
                return map;
            })
            .take(1)
            .doOnNext(map -> {
                System.out.println("doOnNext map.size()=" + map.size());
            })
            .doOnTerminate(() -> {
                System.out.println("doOnTerminate");
            })
            .subscribe();

    final RequestQueue queue = Volley.newRequestQueue(context);
    queue.add(jsonObjectObservableRequest.getJsonObjectRequest());

2 个答案:

答案 0 :(得分:1)

您已正确识别问题,但您未在源网络onCompleted()上调用ObservableJsonObjectObservableRequest类),而take(1)无效因为你把放在 reduce之前 正如您可能已经理解的那样,reduce必须在Observable上以有限的排放量运行,因为它在发出所有项目时发出累积的项目,因此它依赖于onCompleted()事件来了解观察的时间流已结束。

  • 我认为在你的情况下,最好的方法是改变JsonObjectObservableRequest的运行方式,你不需要Subject,你可以使用创建方法来包装一个回调(你可以看到我的回答here,并阅读更多关于回调世界与RxJava here之间的桥接。
  • 此外,您不需要发出Observable某个内容,然后将flatmap发送到项目,您只需使用onNext()发出项目并使用{{发出错误1}},实际上你正在隐藏错误并将它们转换为发射,这可能会使得在流中处理错误变得更加困难。
  • 致电onError()表示完成后,您应在onCompleted()致电onResponse()。如果出现错误,信令onNext()将通知终止流。
  • 另一个问题是取消似乎没有以这种方式处理的请求,你可以阅读这些来源,看看在包装callbacl时如何做到这一点。

答案 1 :(得分:0)

我找到了一种方法来调用doOnTerminate()和doOnNext()。它是在流处理中将take(1)语句放在更高的位置。我根据@yosriz的评论得到了这个想法。我希望我理解为什么这解决了这个问题,但我没有,因为我认为终止信号只会传播,但我想还有很多我需要了解ReactiveX /反应函数编程/等等。< / p>

JsonObjectObservableRequest调用代码

import com.android.volley.Request;
import com.android.volley.RequestQueue;
...
    JsonObjectObservableRequest jsonObjectObservableRequest = new JsonObjectObservableRequest(Request.Method.GET, idURLString, null, keyId, key);
    Observable<JSONObject> jsonObjectObservable = jsonObjectObservableRequest.getObservable();

jsonObjectObservable
        .map(json -> {
            try {
                return NetworkAccountIdDatasource.parseIdJSON(json);
            } catch (JSONException e) {
                e.printStackTrace();
                return null;
            }
        })
        .take(1) // SOLUTION: MOVED THIS UP FROM BELOW reduce()
        .flatMapIterable(x -> x)
        .map(s -> new AbstractMap.SimpleEntry<String, String>("Name of " + s, "short id for " + s.substring(4)))
        .reduce(new HashMap<String, String>(), (map, e) -> {
            map.put(e.getKey(), e.getValue());
            return map;
        })
        // .take(1) // SOLUTION: MOVE THIS ABOVE flatMapIterable() 
        .doOnNext(map -> {
            System.out.println("doOnNext map.size()=" + map.size());
        })
        .doOnTerminate(() -> {
            System.out.println("doOnTerminate");
        })
        .subscribe();

final RequestQueue queue = Volley.newRequestQueue(context);
queue.add(jsonObjectObservableRequest.getJsonObjectRequest());

此外,如果我在第一个map()操作(调用parseIdJSON()的操作之前)将take(1)作为第一个操作,它也可以工作。但是,如果我把take(1)作为reduce()之前的操作,它只能部分工作;好的是doOnNext()被调用但是坏的是map.size()总是1,当我的数据集应该是98时。