Android RxJava在map函数中异步调用

时间:2017-01-17 03:42:59

标签: java android rx-java rx-android

在更改" SortBy"上,我的程序将执行NetworkIO以检索热门电影并显示它们。

但是,似乎虽然我已完成subscribeOn(Schedulers.io()),但MovieDB.getPopular()中的MovieDB.getTopRated()函数中的NetworkIO callmap已在主要内容中执行线程,我得到android.os.NetworkOnMainThreadException

我想知道如何使public Movie[] call(SortBy sortBy)异步。

sortObservable.map(new Func1<SortBy, Movie[]>() {
    @Override
    public Movie[] call(SortBy sortBy) {
        try {
            switch (sortBy) {
                case POPULAR:
                    return MovieDB.getPopular(); // NETWORK IO
                case TOP_RATED:
                    return MovieDB.getTopRated(); // NETWORK IO
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return new Movie[0];
    }
})
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<Movie[]>() {
            @Override
            public void call(Movie[] movies) {
                imageAdapter.loadData(movies);
            }
        });

2 个答案:

答案 0 :(得分:1)

最后,我自己解决了这个问题:

sortObservable.flatMap(new Func1<SortBy, Observable<Movie[]>>() {

    @Override
    public Observable<Movie[]> call(SortBy sortBy) {
        switch (sortBy) {
            case POPULAR:
                return Observable.fromCallable(() -> MovieDB.getPopular()).subscribeOn(Schedulers.io());
            case TOP_RATED:
                return Observable.fromCallable(() -> MovieDB.getTopRated()).subscribeOn(Schedulers.io());
            default:
                return Observable.fromCallable(() -> new Movie[0]).subscribeOn(Schedulers.io());
        }
    }
})
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<Movie[]>() {
            @Override
            public void call(Movie[] movies) {
                imageAdapter.loadData(movies);
            }
        });

答案 1 :(得分:0)

请检查以下内容是否适合您。它使用flatMap代替map

sortObservable.flatMap(new Func1<SortBy, Observable<Movie[]>>() {

        @Override
        public Observable<Movie[]> call(SortBy sortBy) {
            try {
                switch (sortBy) {
                    case POPULAR:
                        return Observable.just(MovieDB.getPopular()); // NETWORK IO
                    case TOP_RATED:
                        return Observable.just(MovieDB.getTopRated()); // NETWORK IO
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return Observable.just(new Movie[0]);
        }
    }).subscribe(new Action1<Movie[]>() {
        @Override
        public void call(Movie[] movies) {
            imageAdapter.loadData(movies);
        }
    });

从Github上的源代码中,您似乎正在使用OkHttp执行请求的同步模式。 OkHttp还支持异步请求,这可能是首选。以下是几种方法所需的变化。

  1. run方法应使用enqueue代替execute

    Observable<String> runAsync(String url){
    return Observable.create(subscriber -> {
        Request request = new Request.Builder().url(url).build();
    
        client.newCall(request).enqueue(new Callback() {
    
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                subscriber.onNext(response.body().string());
            }
    
            @Override
            public void onFailure(Call call, IOException e) {
                subscriber.onError(e);
            }
        });
    });
    }
    
  2. getApi可以返回Observable<Movie[]>而不是Movie[]

    public Observable<Movie[]> getApiAsync(String type){
    return runAsync("http://api.themoviedb.org/3/movie/" + type
            + "?api_key=412e9780d02673b7599233b1636a0f0e").flatMap(response -> {
                Gson gson = new Gson();
                Map<String, Object> map = gson.fromJson(response,
                        new TypeToken<Map<String, Object>>() {
                        }.getType());
                Movie[] movies = gson.fromJson(gson.toJson(map.get("results")),
                        Movie[].class);
                return Observable.just(movies);
            });
    }