【问题标题】:How can I get the results returned by a map function with RxJava?如何使用 RxJava 获取 map 函数返回的结果?
【发布时间】:2015-07-19 16:28:48
【问题描述】:

作为我的 API 调用的一部分,我使用 RxJava 的 map 函数从响应 JSON 中创建图像 URL 列表来获取多媒体信息列表。如何处理从 map 函数返回的列表?这是我的代码:

BrowseAPI service = CKApplication.getInstance().getRestAdapter().create(BrowseAPI.class);
BrowseRequest request = new BrowseRequest("0","50","true","A");
service.getMultmedia(MyApplication.getInstance().getJSessionID(), request).map(new Func1<Multimedia, Object>() {
    @Override
    public Object call(Multimedia multimedia) {
        ArrayList<String> imageURLs = new ArrayList<String>();
        for(MultiMediaImage image : multimedia.getResultsWrapper().getMultiMediaImage()) {
            String url = "https://xxxxxxx/service/content/imageByEntitlement/";
            url += image.getEid();
            url +="?thumbnail=true";
            imageURLs.add(url);
        }
        return imageURLs;
    }
}).subscribe(multimedia -> {
    Log.d("dfa", "adga");
});

我能够从响应中创建 URL 的字符串列表,我想在单独的活动或片段中处理这个 URL 列表。

使用flatMap,我相信这可以改进:

BrowseAPI service = CKApplication.getInstance().getRestAdapter().create(BrowseAPI.class);
BrowseRequest request = new BrowseRequest("0","50","true","A");
service.getMultmedia(CKApplication.getInstance().getJSessionID(), request).flatMap(new Func1<Multimedia, Observable<MultiMediaImage>>() {
    @Override
    public Observable<MultiMediaImage> call(Multimedia multimedia) {
        Observable<MultiMediaImage> observable = Observable.from(multimedia.getResultsWrapper().getMultiMediaImage());
        return observable;
    }
}).subscribe(new Action1<MultiMediaImage>() {
    @Override
    public void call(MultiMediaImage multiMediaImage) {
        service.getImageObject(CKApplication.getInstance().getJSessionID(), multiMediaImage.getEid()).observeOn(AndroidSchedulers.mainThread()).subscribe(imageObject -> {
            mImages.add(imageObject.getAuthenticatedStoreUrl());
            adapter.notifyDataSetChanged();
        });
    }
});

【问题讨论】:

  • 1.) 你有什么理由不使用Func1&lt;Multimedia, List&lt;String&gt;&gt; 而只是返回Objects? 2.) 你到底在哪里遇到问题?您可以在Activity/Fragment 中获得对Observable 的引用并在那里订阅?
  • 谢谢 Mattia ,我会尝试观察活动。如果是 Func1> ,我如何访问 List 的值
  • 我仍然不确定我是否理解您所说的“我如何访问它们”的意思——您将它们作为您的 onNext 方法的参数交给您。在您的示例中,multimedia 变量将包含您的Func1 的结果。不管你returncall 方法都会传递给onNext
  • 基本上,我在这里想要实现的是,getMultmedia() 返回一个带有 MultiMediaImage 对象列表的 json 响应,其中只有图像的 ID。我正在解析 getMultiMedia() 响应并使用 ID 创建 URL 的数组列表。一旦我有了 URL 的数组列表,我必须使用经过身份验证的标头进行另一个 api 调用,这将返回带有实际图像 URL 的 json 响应。我必须进行两次背靠背 api 调用才能获取实际的图像 URL。
  • 在这种情况下,请查看flatMap - 在您的情况下,您可能希望连续使用它两次:首先将Observable&lt;List&lt;String&gt;&gt; 平面映射到Observable&lt;String&gt;,然后实际执行您对每个 Strings 的第二次 API 调用。

标签: android retrofit rx-java rx-android


【解决方案1】:

这个怎么样?

Observable<Multimedia> multimediaObservable = service.getMultmedia(MyApplication.getInstance().getJSessionID(), request);

Subscription subscription = bindFragment(this, multimediaObservable
.observeOn(AndroidSchedulers.handlerThread(new Handler()))
.map(new Func1<Multimedia, ArrayList<String>>() {
    @Override
    public ArrayList<String> call(Multimedia multimedia) {
        ArrayList<String> imageURLs = new ArrayList<String>();
        for(MultiMediaImage image : multimedia.getResultsWrapper().getMultiMediaImage()) {               
            imageURLs.add(makeImageUrl(image);
        }
        return imageURLs;
    }
})).subscribe(multimediaArrayList -> {
    //do something with the list
});

...
private String makeImageUrl(MultiMediaImage image){
    String url = "https://xxxxxxx/service/content/"
    url += image.getEid();
    url +="?thumbnail=true";
    return url;
}

或者使用您在 subscribe() 方法中使用的 Java8 语法:

.map(multimedia -> {
    ArrayList<String> imageURLs = new ArrayList<String>();
    for(MultiMediaImage image : multimedia.getResultsWrapper().getMultiMediaImage()) {               
        imageURLs.add(makeImageUrl(image);
    }
    return imageURLs;        
})

一些注意事项:

  • 我假设 mediaObservable 是一个不应该在主线程中完成的网络调用。如果它是从 Retrofit 发出的 observable,你不必担心有一个单独的异步线程。

  • bindFragment() 是 RxAndroid 库的一部分,它会自动 “观察”主线程()。对于活动,请使用 bindActivity()。或者使用 observeOn(mainThread())。

  • 没有必要像第二个示例那样使用 flatmap,因为它无需将对象转换为 observable 并返回到普通对象(地图可以直接接收)。

  • 不要忘记 subsribe() 中的 onError。

更新:

您可以使用from() 来展平数组并处理订阅中的每个 MultimediaImage 项。

Subscription subscription = bindFragment(this, multimediaObservable
.observeOn(AndroidSchedulers.handlerThread(new Handler()))
.flatMap(multimedia-> 
   Observable.from(multimedia.getResultsWrapper().getMultiMediaImage())
).subscribe(multimediaImage -> {
    //multimediaImage is a MultimediaImage class object
    Log.i("ImageId", multimediaImage.getEid());
});

【讨论】:

  • 谢谢@Diolor。在您的地图示例中,如果没有错,我将不得不等到完整的 imageUrls 列表。我想在创建每个对象时用图像填充列表,而不是等到整个列表被填充。我该怎么做?
  • @r7v 取决于。 Observable&lt;Multimedia&gt; 发出一个多媒体项目,它(根据我的理解)已经创建了一个图像数组列表。因此,如果您想获取新创建的图像,您应该观察列表 (getMultiMediaImage()) 而不是多媒体本身。但这是您代码中更深层次的架构问题 :) 如果您只想从 getMultiMediaImage() 一次拍摄一张图像,请查看上面的更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-29
  • 1970-01-01
  • 2013-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多