【问题标题】:RXJava retrofit waiting having the UI wait for data to be fetched from APIRXJava 改造等待 UI 等待从 API 获取数据
【发布时间】:2020-06-17 23:05:31
【问题描述】:

我正在学习 android 开发我正在使用 RXJava 和改造来与 API 交互。所以我已经成功地从我的 API 获取数据。现在的问题是程序在获取数据之前继续。如何等待从 API 下载数据然后运行某些函数?

我有一个如图所示的改造客户

public class RetrofitClient {

    private static Retrofit retrofit = null;

    private RetrofitClient() {

    }

    public static Retrofit getClient(String baseUrl) {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(SimpleXmlConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

我这样进行 API 调用。

public void getData(MyFragment Fragment) {

        mAPIService.getData()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Data>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.i("ERROR IN GET DATA", e.toString());
                    }
                    @Override
                    public void onNext(Data response) {
                        Log.i("MY DATA", response.toString());
                        fragment.downloadData(response);
                    }

                });
}

问题是我的 android 应用程序没有等待 fragment.downloadData(response) 完成,而是继续执行代码,然后因为响应为空而崩溃。

我在一个按钮上有一个监听器,当点击它时会从 API 获取数据

    button.setOnClickListener(v ->{

        APICaller.getData(this);
        Log.i("TEST", data.ToString()); //THIS IS NULL

        });

这是我从 APICaller 运行的 downloadData 函数

  public void downloadData(Data data) {
        this.data = data;
    }

【问题讨论】:

    标签: java android api retrofit


    【解决方案1】:

    您需要等待 RxJava 流发出一个值(错误或响应)。

    首先,为此,如果您期望“单一”发射,成功或失败,我会使用Single。目前看起来你的mAPIService.getData() 方法正在返回一个Observable。这些适用于将发出多个值的流,在您的原因中我假设这不会发生。您只有一个要发出的项目,所以我会考虑返回一个Single。不是您问题的一部分,但仅供参考。

    我喜欢做的是告诉我的 UI,无论我在做什么都是“加载”,通常在 doOnSubscribe 中。然后 UI 知道显示加载图标或不允许用户交互或其他内容。像这样的东西(注意它在observeOn(AndroidSchedulers.mainThread) 之后的方式。任何时候你与 UI 元素交互时,都在主线程上进行。我认为这会做到):

    mAPIService.getData()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .doOnSubscribe(new Consumer<Disposable>() {
                                @Override
                                public void accept(Disposable disposable) throws Exception {
                                    fragment.loading();
                                }
                            })
    

    然后,当 onErroronSuccess 在您的订阅中返回时,您就可以告诉 UI 已准备好继续。然后,您要么有一个有效的响应,要么可以向用户显示错误。

    编辑:反应式编程

    在您的 cmets 之后,您似乎不了解响应式编程。它的学习曲线有点陡峭,我今天仍在努力。

    您的APICaller 类,无论它是什么,都应该返回Observable 本身。您不应该将Fragment 传递给它并在其中处理它,因为您将自己暴露在内存泄漏中并且它有点代码气味。更好的选择是只返回由mAPIService.getData() 返回的Observable。而已。目前,您正在使用Schedulers.io()Observable 推送到另一个线程,这对您的主线程说,继续,不要等我。然后,当使用代码 .observeOn(AndroidSchedulers.mainThread()) 发出响应时,您会返回此线程

    然后在您的片段中处理值或错误的发射。然后您的片段代码变为:

    button.setOnClickListener(v ->{
        APICaller.getData()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Subscriber<Data>() {
                        @Override
                        public void onCompleted() {
    
                        }
    
                        @Override
                        public void onError(Throwable e) {
                            Log.i("ERROR IN GET DATA", e.toString());
                        }
                        @Override
                        public void onNext(Data response) {
                            Log.i("MY DATA", response.toString());
                            this.data = response
                            Log.i("TEST: "+data.toString());
                        }
    
                    });
    
    });
    

    我想推荐你看一些教程,做一些阅读,我还想在开始时向你推荐我关于Singles 的观点

    【讨论】:

    • 好吧,我假设你的意思是我的 onComplete()?通过我如何暂停 UI?我应该只是 while(gettingData) {Sleep}
    • 我已经用doOnSubscribe 的信息更新了答案。我不确定您所说的“暂停”是什么意思。我假设在此 API 调用完成之前,您不希望用户进展。在哪个原因中,在加载时,禁用所有导致需要响应已返回的操作的按钮。
    • 我想暂停的不是用户交互,而是我的应用程序崩溃,因为它在 API 返回任何数据之前尝试处理来自 API 的响应。那么如何让 getData 的调用者等待呢?我认为一次性适用于 RXJava2 吗? RXJava1 中是否有任何等价物?
    • 请通过更新您的问题告诉我您在哪里调用此方法。请提供尽可能多的信息
    • 好的,我更新了原帖。当我点击一个按钮时,我会从 API 下载数据并将其打印到日志中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-26
    • 1970-01-01
    • 2022-07-06
    • 1970-01-01
    • 2019-10-02
    • 1970-01-01
    相关资源
    最近更新 更多