首页 > 解决方案 > rxjava2中的zip函数问题

问题描述

似乎 zip 函数没有做任何事情。带有 TAG INSIDE 的请求日志打印出 observables 但在 OUTSIDE 是空的。在 zip 函数中,LOG 调用不做任何事情。getPosts 返回 id 列表。我是 Android 的初学者,所以也许我比我能用 Rxjava 咀嚼更多,但显然这是最好的解决方案。本质上,getPosts返回一个 id 列表,我应该用它来编写进一步的请求。getStory如果有更简单的我渴望听到它。谢谢。

主要活动

package com.example.hackernews;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

import static java.lang.Math.min;

public class MainActivity extends AppCompatActivity {
    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
    private  List<DataResponse> dataResponses;
    private Observable<List<Integer>> ids;
    private List<Observable<DataResponse>> requests = new ArrayList<>();

    @SuppressLint("CheckResult")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);




//        mRecyclerView = findViewById(R.id.recyclerView);
//        mRecyclerView.setHasFixedSize(true);
//        mLayoutManager = new LinearLayoutManager(getApplicationContext());
//        mRecyclerView.setLayoutManager(mLayoutManager);



        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .build();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://hacker-news.firebaseio.com/v0/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(client)
                .build();

        HackerNewsApi hackerNewsApi = retrofit.create(HackerNewsApi.class);

        ids = hackerNewsApi.getPosts();

        ids.subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .subscribe(id -> {
                    for (Integer i : id) {
                        requests.add(hackerNewsApi.getStory(i));
                    }
                    Log.e("onSubscribe", "INSIDE " + requests);
                }, Throwable::printStackTrace);
        Log.e("onSubscribe", "OUTSIDE " + requests);

        Observable.zip(
                requests,
                new Function<Object[], Object>() {
                    @Override
                    public Object apply(Object[] objects) throws Exception {
                        // Objects[] is an array of combined results of completed requests

                        Log.e("onSubscribe", "YOUR OBJECTS ARE HERE: " + objects);
                        // do something with those results and emit new event
                        return new Object();
                    }
                })
                // After all requests had been performed the next observer will receive the Object, returned from Function
                .subscribe(
                        // Will be triggered if all requests will end successfully (4xx and 5xx also are successful requests too)
                        new Consumer<Object>() {
                            @Override
                            public void accept(Object o) throws Exception {
                                //Do something on successful completion of all requests
                                Log.e("onSubscribe", "YOUR OBJECTS ARE HERE: " + o);
                            }
                        },

                        // Will be triggered if any error during requests will happen
                        new Consumer<Throwable>() {
                            @Override
                            public void accept(Throwable e) throws Exception {
                                //Do something on error completion of requests
                            }
                        }
                );


//            mRecyclerView = findViewById(R.id.recyclerView);
//            mRecyclerView.setHasFixedSize(true);
//            mLayoutManager = new LinearLayoutManager(this);
//            Log.e("onSubscribe", "YOUR DATA IS HERE: " + dataResponses);
//            mAdapter = new ExampleAdapter(dataResponses);
//
//
//            mRecyclerView.setLayoutManager(mLayoutManager);
//            mRecyclerView.setAdapter(mAdapter);


    }

}

HackerNewsApi

package com.example.hackernews;

import java.util.List;

import io.reactivex.Observable;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;

public interface HackerNewsApi {

    @GET("askstories.json?print=pretty")
    Observable<List<Integer>> getPosts();

    @GET("item/{id}.json?print=pretty")
    Observable<DataResponse> getStory(@Path("id") Integer id);
}

标签: javaandroidretrofitrx-java2

解决方案


您在后台创建一个故事检索 observables 的列表,并同时尝试使用在主线程上构建的列表。

为什么不简单地作曲getPosts()呢?

 hackerNewsApi.getPosts()
 .subscribeOn(Schedulers.io())
 .flatMapIterable(posts -> posts)
 .flatMap(post -> hackerNewsApi.getStory(post))
 .toList()
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(allStories -> { /* ... */ }, error -> { /* ... */ });

flatMapIterable展开您的初始帖子列表并按toList某种顺序重新组合它们。


推荐阅读