Android,Retrofit,RxJava - 将来自多个实体的字段组合成单个实体

时间:2017-06-19 06:13:00

标签: java android retrofit rx-java2

请查看下面的代码。我从城市检索类别的代码:

mcityAPI.authDevice(req)
                    .subscribeOn(Schedulers.io())
                    .flatMap(token -> mcityAPI.getCategories("/city/599/category",prepareHeaders(token)))
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(categoryList->
                    {
                        HashMap<String, String> categoryNamesMap = new HashMap<>();
                        for (Category category : categoryList)
                        {
                            categoryNamesMap.put(category.getId(), category.getName());
                        }

                    }

                    , throwable ->
                    {
                        Throwable error = throwable;
                        String err = error.toString();
                    });

因此,首先需要授权设备 - authDevice。然后,需要提供令牌来调用getCategories(实际上,应该首先通过调用prepareHeaders将令牌转换为头文件)

到目前为止,它有效。我能够成功加载类别。下一步是获取事件。在这种情况下,我应该调用/city/599/event,但我需要这样做:

  • 再次提供标题(如何访问以前检索过的标记?)
  • 我的事件的pojo模型类包含额外的字段,称为categoryName。每个返回的事件都将包含名为categoryId的字段。我还添加了一个额外的字段categoryName。对于每个返回的类别,我需要为categoryName额外字段分配适当的值。类别名称应通过categoryList
  • categoryId检索

有没有任何优雅的方式(一些rxJava运算符等)允许做我想要的?

2 个答案:

答案 0 :(得分:2)

据我所知,你的令牌是每台设备所以你可以存储它以便以后使用它。

首先:

  • 获取您的令牌并将其存储在例如SharedPreferences中。这将使您可以从所需的每个位置访问令牌。

其次:

  • 现在,您可以在同一个流中发出两个请求。

  • 请记住正确使用subscribeOn。它仅在上游和observeOn下游工作。这意味着您要求MainTread,因此您应该更改它。

  • 您可以使用operator map来获取categoriesMap;

  • 您应该注意错误处理,因为一次失败会取消订阅您的信息流,因此无法再次使用。

      triggerSubject
                    .flatMap(token -> mcityAPI.getCategories("/city/599/category",prepareHeaders(sharedPreferences.getToken())))
                    .map(categoryList -> {
                        final HashMap<String, String> categoryNamesMap = new HashMap<>();
                        for (Category category : categoryList)
                        {
                            categoryNamesMap.put(category.getId(), category.getName());
                        }
                        return categoryNamesMap;
                    })
                    .flatMap(cateogyrNameMap -> yourApiCall, prepareHeaders(sharedPreferences.getToken()))
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .retry()
                    .subscribe(event -> {
                        // Do what you need
                    }

                    , throwable ->
                    {
                        Throwable error = throwable;
                        String err = error.toString();
                    });

答案 1 :(得分:1)

你可以复制第一部分,再次平面图并将两个观察者与Zip operator

结合起来

但它在性能方面表现不佳

您可以做的是使用相同的令牌observable来触发这两个请求。因此,通过将第一个Observable<Token>转换为热的可观察对象,您可以在不启动请求两次的情况下使用它:

Observable<Token> obsToken = mcityAPI.authDevice(req)
                                 .share();       // So the authDevice method is only invoqued once
// Assumming your Category's ID is an Integer
Observable<Map<Integer, Category>> obsCategories = obsToken
                                           .flatMap(token -> mcityAPI.getCategories("/city/599/category",prepareHeaders(token)))
                                           .toList()     // So we have all categories
                                           .map(categoryList -> {
                                               Map<Integer, Category> result = new HashMap<>();
                                               for (Category c : categories)
                                                   result.put(c.getId(), c);
                                               return result;
                                           })
                                           .subscribeOn(Schedulers.io());
Observable<List<Event>> obsEvents = obsToken
                                   .flatMap(token -> mcityAPI.getEvents("/city/599/eventprepareHeaders(token)))
                                   .toList()             // So we have all events
                                   .subscribeOn(Schedulers.io());
Observable<?> result = Observable.zip(obsCategories, obsEvents, (categories, events) -> {
    // now you have all categories and events
    // you can now fill category name by looking into the first map
    for (Event e : events)
        events.forEach(event -> 
            event.setCategoryName(
                categories.get(event.getCategoryId()).getName()
                )
        );
    // Do the rest of mapping and return something...
}