对于处理RxJava中的错误和异常感到困惑

时间:2016-11-06 14:47:14

标签: android rx-java

我刚刚开始学习RxJava,我已经阅读并观看了不少教程,但有些事情还没有点击。我已经深入了解并开始修改我的应用程序的一个API调用以返回一个Observable。目前,API调用由AsyncTaskLoader使用,它从本地数据库返回缓存数据,然后进行调用,合并数据并再次返回。这个模式听起来像是我的RxJava实验的完美主题,但从小开始,我想从我的API调用中返回一个observable。

这是我原来的电话:

public static ArrayList<Stuff> getStuffForId(String id)
        throws IOException, UserNotAuthenticatedException {
    Profile profile = getProfile();
    HashMap<String,ArrayList<Stuff>> map = profile.getStuff();
    if (map == null) {
        throw new IOException("error processing - map cannot be null");
    }
    return map.get(id);
}

private static Profile getProfile() 
        throws IOException, UserNotAuthenticatedException {

    // <.. getting url, auth tokens and other stuff to prepare the Request ..>

    Response response = sHttpClient.newCall(request).execute();
    if (response.code() == ERR_AUTH_REJECTED) {
        throw new UserNotAuthenticatedException(response.body().string());
    }
    if (!response.isSuccessful()) {
        throw new IOException("Unexpected code " + response);
    }
    Gson gson = new Gson();
    String result = response.body().string();
    response.body().close();
    return gson.fromJson(result, Profile.class);
}

在RxJava世界中,我正在思考以下几点:

public static Observable<ArrayList<Stuff>> getStuffForId(String id) {
    return getProfile().map(
            Profile::getStuff).map(
            map -> {
                if (map == null) {
                    Observable.error(new IOException("error processing - map cannot be null"));
                }
                return map.get(id);
            });
}

private static Observable<Profile> getProfile() {
    return Observable.fromCallable(() -> {

        // <.. getting url, auth tokens and other stuff to prepare the Request ..>

        Response response = sHttpClient.newCall(request).execute();
        if (response.code() == ERR_AUTH_REJECTED) {
            throw new UserNotAuthenticatedException(response.body().string(),
                    authToken);
        }
        if (!response.isSuccessful()) {
            throw new IOException("Unexpected code " + response);
        }
        Gson gson = new Gson();
        String result = response.body().string();
        response.body().close();
        return gson.fromJson(result, Profile.class);
    });
}

这看起来像人们期望的那样吗?我仍然不确定fromCallable()defer()之间的区别以及您使用哪一个。还不确定在fromCallable()方法中抛出异常的位置 - 它们会自动结束我的订阅者的onError还是我需要在我的getStuffForId方法中处理它们?最后,Android Studio警告我return map.get(id)可能会抛出nullPointer。这只是因为IDE不理解Observable.error将终止执行,还是因为我不明白Observable.error会发生什么?

2 个答案:

答案 0 :(得分:2)

1)差异b / w fromCallable()defer()

Well defer()在某些订阅者订阅之前不会创建Observable,并且每次用户订阅时都会创建新的Obervable。请参阅此link,了解您希望使用defer()的原因。

2)在fromCallable()方法中抛出异常的位置在哪里?

异常会在Observer中捕获,然后作为Throwable对象传递给Subscriber的onError()方法。

3)Android Studio警告我return map.get(id)可能会抛出nullPointer。

因为当它实际为null时,你不会在if语句中返回任何内容。代码将超出if语句,从而导致nullPointerException。 Observable.error());返回一个Observable并且它不会抛出任何东西,为了做到这一点,你必须显式抛出RuntimeException。

4)这看起来与人们期望的一样。

除了上述错误之外,没有任何错误,但您可以在线搜索rxJava模式以便在结构上进行更好的编码。

答案 1 :(得分:1)

  1. 这看起来像人们期望的那样
  2. 是的,但是请看一下图书馆,这些图书馆会为你做管道工作:https://github.com/square/retrofit 如果你在fromCallable中抛出任何异常,你将使用defer并返回Observable.error(new Exception(&#34; error&#34;))

    1. 与可录/延迟的区别
    2. 这两种方法都是用于创建可观察对象的工厂。从callable要求你返回一个像字符串等的值。推迟像你一样返回一个可观察到的东西。如果你想包装一些返回某种类型的非observable-method-call,你可以使用fromCallable。此外,fromCallable将处理您的异常并将其传递给链。相反,如果您想处理自己的异常/可观察对象,则会使用延迟。您可以返回一个发出值的observable,然后完成或不完成。 &#39; fromCallable&#39;我们将完成一个值和onComplete或onError。延迟时,你可以产生一个observable,它永远不会像在Observable.never()中那样结束。

      1. 他们会自动结束onError
      2. 是的,异常将被捕获并传递为onError。您可以立即在链中使用操作符处理错误,也可以在订阅时提供onError句柄(重载)。

        1. return map.get(id)可能会抛出nullPointer
        2. 如果您使用的是RxJava1.x,则可能会在流中遇到空值,因为使用onNext(null)传递值是有效的。因此,由于NPE的可能性,您需要进行空检查。您可以使用filter-operator过滤掉null值,而不是使用null检查:

              Observable.just("1", "2", null, "3")
                      .filter(s -> s != null)
                      .map(s -> s.getBytes())
                      .subscribe(bytes -> {
                          //...
                      });
          

          在这种情况下,您将收到有关s.getBytes()可能的NPE的警告。但是由于过滤操作,你可以肯定,s永远不会为空。