使用Retrofit和RxJava从Android中的JSON数组逐个获取JSON对象

时间:2016-09-05 12:48:42

标签: android json rx-java retrofit2 rx-android

我正在使用改造来点击返回json数组的网络api。我这样做是使用以下代码 -

Observable<MyJson[]> response = (Observable<MyJson[]>)mNetworkService.getReadyObserverable(mNetworkService.getNetworkServiceApi().getMyDataJsons(), MyJson.class, true, useCache);
        mAirlineSubscription = response.subscribe(new Observer<MyJson[]>() {
            @Override
            public void onCompleted() {
                Log.d(TAG, "getData completed..");
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: "  + e.getLocalizedMessage());
            }

            @Override
            public void onNext(MyJson[] myJsonData) {
                //I want here json data one by one
            }

但我的问题是json数据数组完全下载然后才下载 onNext被调用。在这里,我希望在改装从onNext json数组中下载第一个json对象时调用myData[]并保持继续直到我的myData[]的所有json对象都被下载。这样,我的UI在用户交互方面看起来会更具响应性和更好。

任何人都可以帮忙解决这个问题吗?

3 个答案:

答案 0 :(得分:1)

您的服务应如下所示:

@GET("users/{username}/repos")
Observable<List<Repository>> publicRepositories(@Path("username") String username);

我的意思是,返回Observable<List<Something>>

答案 1 :(得分:1)

尽可能快地逐个接收元素?
不想等待下载所有内容?

解决方案是:使用注释@Streaming声明改造界面的方法,并使用Observable<ResponseBody>作为返回值。然后,使用flatMap(),将ResponseBody转换为POJO系列(Observable<TYPE>)。

示例:

  1. 声明改造界面:

    public interface HugeJsonApi {
    
    String SERVICE_ENDPOINT = "https://raw.githubusercontent.com";
    
    @Streaming
    @GET("/zemirco/sf-city-lots-json/master/citylots.json")
    Observable<ResponseBody> get();
    }

  2. 使用它:

    public void playHugeJsonSample() {
    
        HugeJsonApi hugeJsonApi = RestUtils.createService(HugeJsonApi.class, HugeJsonApi.SERVICE_ENDPOINT);
    
        Handler handler = new Handler(Looper.getMainLooper());
        hugeJsonApi.get()
                .flatMap(responseBody -> convertObjectsStream(responseBody, gson, Feature.class))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Feature>() {
    
                    @Override
                    public void onStart() {
                        super.onStart();
                        request(1);
                    }
    
                    @Override
                    public void onNext(Feature feature) {
                        Log.i(TAG, gson.toJson(feature));
                        counter[0]++;
                        request(1);
                    }
    
                    @Override
                    public void onCompleted() {
                        Log.i(TAG, "onCompleted() called. Fetched elements:" + counter[0]);
                    }
    
                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "something went wrong", e);
                    }
                });
    }
    
    @NonNull
    private static <TYPE> Observable<TYPE> convertObjectsStream(ResponseBody responseBody, Gson gson, Class<TYPE> clazz) {
        Type type = TypeToken.get(clazz).getType();
        return Observable.create(SyncOnSubscribe.<JsonReader, TYPE>createStateful(
                // initialize the reader
                () -> {
                    try {
                        JsonReader reader = gson.newJsonReader(responseBody.charStream());
                        reader.beginObject();
                        return reader;
                    } catch (IOException e) {
                        e.printStackTrace();
                        RxJavaHooks.onError(e);
                    }
                    return null;
                },
                // read elements one by one
                (reader, observer) -> {
    
                    if (reader == null) {
                        observer.onCompleted();
                        return null;
                    }
    
                    try {
                        if (reader.hasNext()) {
                            TYPE t = gson.fromJson(reader, type);
                            observer.onNext(t);
                        }
                        else {
                            observer.onCompleted();
                        }
    
                    } catch (IOException e) {
                        e.printStackTrace();
                        observer.onError(e);
                    }
    
                    return reader;
                },
                // close the reader
                reader -> {
                    if (reader != null) {
                        try {
                            reader.close();
                        } catch (Exception e) {
                            e.printStackTrace();
                            RxJavaHooks.onError(e);
                        }
                    }
                }
    
        ));
    }

  3. 以下是可行的示例:

    https://github.com/allco/RetrofitAndRxJava

    它需要180 + Mb Json并将其解析为真正的流。

答案 2 :(得分:1)

我有同样的问题我解释它自己项目的基础,你应该使用 我的改装要求是

@GET("StudentApi/getAll")
    Observable<List<Person>> getPersons();

我有一个运行服务器请求的接口,它有这个方法来运行getPersons()并返回json数组信息列表

Observable<Person> getAllPersons();

并且重要的部分是up方法的身体,并且应该像下面

@Override
    public Observable<Person> getAllPersons() {
        Observable<List<Person>> observable =
                serviceGenerator.getService().getPersons();
        return observable
                .flatMap(new Function<List<Person>, Observable<Person>>() {
                    @Override
                    public Observable<Person> apply(List<Person> persons) throws Exception {
                        return Observable.fromIterable(persons);
                    }
                });
}

我发现fromIterable方法一个接一个地返回json数组的对象 最后在一个活动中,我从诸如bellow

之类的向上方法中获取json对象
public void getPersons(){
      personsRepository.getAllPersons()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribeWith(new DisposableObserver<Person>() {
                    @Override
                    public void onNext(Person value) {
                        Log.e("person info  is",value.getpName() + value.getpFamily());
                    }

                    @Override
                    public void onError(Throwable throwable) {
                        Log.e("onError",throwable.toString());
                    }

                    @Override
                    public void onComplete() {
                        Log.e("onComplete","onComplete");
                    }
                });
    }

我希望有用:)