RxJava / Retrofit API调用未知大小列表中的每个项目

时间:2018-06-22 16:44:01

标签: android api rx-java retrofit2 rx-java2

我目前正在首次尝试将RxJava与Retrofit结合使用,但似乎无法满足我的特定用例的要求:

我首先使用改造来调用API,以向用户所在位置附近的电影院放映电影。 然后,我使用用户单击的电影院ID来显示该电影院的放映时间,即...

public interface ListingApiService
{
    @GET("/get/times/cinema/{id}")
    Call<ListingResponse> getShowtimes (@Path("id") String id);
}


Then using the interface....


public void connectAndGetApiData(String id)
    {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }

        ListingApiService listingApiService = retrofit.create(ListingApiService.class);

        Call<ListingResponse> call = listingApiService.getShowtimes(id);
        call.enqueue(new Callback<ListingResponse>() {
            @Override
            public void onResponse(Call<ListingResponse> call, Response<ListingResponse> response)
            {
                List<Listing> listings = response.body().getListings()
                getAndDisplayImage(listings.get(0).getTitle());
        recyclerView.setAdapter(new ListingAdapter(listings,R.layout.list_item_listing,getApplicationContext()));

            }

            @Override
            public void onFailure(Call<ListingResponse> call, Throwable t)
            {
                Log.e(TAG,t.toString());

            }
        });
    }

然后,我想调用一个不同的API(上下文网络搜索)以显示每个电影列表的相关电影海报的图像(只是为了获得良好的视觉效果)。我知道如何为单个图像调用API,但是我不知道如何进行多个调用。我尝试使用Internet上其他地方找到的RxJava代码,但似乎都不起作用,因为我不知道我将要拨打多少电话或搜索字词是什么。我用于单次通话的代码是:

public interface ListingImageApiService
{
    //https://contextualwebsearch-websearch-v1.p.mashape.com/api/Search/ImageSearchAPI?count=1&autoCorrect=false&q=Donald+Trump
    @Headers("X-Mashape-Key: apikey")
    @GET("/api/Search/ImageSearchAPI?count=5&autoCorrect=false")
    Call<ListingImageResponse> getListingImages (@Query("q") String term);
}


 public void getAndDisplayImage(String search)
    {
        if (retrofit2 == null)
        {
            retrofit2 = new Retrofit.Builder()
                    .baseUrl(BASE_URL2)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }

    search = search + " poster";
    ListingImageApiService listingImageApiService = retrofit2.create(ListingImageApiService.class);


    Call<ListingImageResponse> call = listingImageApiService.getListingImages(search);
    call.enqueue(new Callback<ListingImageResponse>() {
        @Override
        public void onResponse(Call<ListingImageResponse> call, Response<ListingImageResponse> response)
        {
            System.out.println(response.body().toString());
            ListingImage a = new ListingImage();
            List<ListingImage> listingImages = response.body().getListingImage();
            System.out.println(listingImages.get(0).getUrl());

        }

        @Override
        public void onFailure(Call<ListingImageResponse> call, Throwable t) 
        {

        }
    });
}

我的问题是,我将如何使用RxJava使用未知大小的电影标题列表的数据进行多次调用(可以将其传递给getAndDisplayImage而不是单个字符串)?我做了几次尝试,但是似乎都没有用到我的用例。谢谢。

1 个答案:

答案 0 :(得分:2)

这种设计应该可以解决您的问题。

此接口包含应用程序中使用的端点。

public interface ListingApiService
{
    @GET("/get/times/cinema/{id}")
    Observable<List<MovieResponse>> getShowtimes (@Path("id") String id);

    @Headers("X-Mashape-Key: apikey")
    @GET("/api/Search/ImageSearchAPI?count=5&autoCorrect=false")
    Observable<ListingImageResponse> getListingImages (@Query("q") String term);
}

提供改造对象以进行呼叫的方法

private API getAPI() {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("<your API endpoint address")
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build();

    return retrofit.create(API.class);
}

拨打电话以获取List<MovieResponse>。此方法还将List转换为单个可观察的MovieResponse对象。

private void getMovieListingsWithImages() {
    Observer<MovieResponse> observer = new Observer<MovieResponse>() {
        @Override
        public void onSubscribe(Disposable d) {
            Toast.makeText(getApplicationContext(), "", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onNext(MovieResponse movieResponse) {
            //for each movie response make a call to the API which provides the image for the movie
        }

        @Override
        public void onError(Throwable e) {
            Toast.makeText(getApplicationContext(), "Error getting image for the movie", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onComplete() {
            Toast.makeText(getApplicationContext(), "Finished getting images for all the movies in the stream", Toast.LENGTH_SHORT).show();
        }
    };

    getAPI().getShowtimes()
            .flatMapIterable(movieResponseList -> movieResponseList) // converts your list of movieResponse into and observable which emits one movieResponse object at a time.
            .flatMap(this::getObservableFromString) // method converts the each movie response object into an observable
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(observer);
}

MovieResponse对象转换为Observable对象的方法。

private Observable<MovieResponse> getObservableFromString(MovieResponse movieResponse) {
    return Observable.just(movieResponse);
}