RX Java ожидание дооснащения, когда пользовательский интерфейс ожидает извлечения данных из API - PullRequest
1 голос
/ 05 марта 2020

Я изучаю android Разработка Я использую RX Java с модернизацией для взаимодействия с 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 приложение не ждет фрагмента. DownloadloadData (ответ) на fini sh, а вместо этого продолжает выполнение кода, а затем вылетает из-за отсутствия ответа.

У меня есть прослушиватель для кнопки, которая при нажатии получает данные из API

    button.setOnClickListener(v ->{

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

        });

Это функция downloadData, которую я запускаю из APICaller

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

1 Ответ

0 голосов
/ 05 марта 2020

Вам нужно дождаться, пока ваш поток Rx Java выдаст значение (либо ошибку, либо ответ).

Во-первых, для этого, если вы ожидаете "одиночного" выброса, успеха или неудачи, я бы использовал Single. В данный момент похоже, что ваш mAPIService.getData() метод возвращает Observable. Они предназначены для потоков, которые будут излучать несколько значений, что, как я полагаю, не является причиной того, что произойдет. У вас есть только один предмет, который будет выпущен, поэтому я бы посмотрел на возвращение Single. Не часть вашего вопроса, но к вашему сведению.

Что мне нравится делать, так это сообщать моему интерфейсу, что все, что я делаю, это «загрузка», обычно в doOnSubscribe. Тогда пользовательский интерфейс знает, чтобы показать значок загрузки или запретить взаимодействие с пользователем или что-то. Примерно так (заметьте, как это после observeOn(AndroidSchedulers.mainThread). Каждый раз, когда вы взаимодействуете с элементами пользовательского интерфейса, делайте это в главном потоке. Я думаю, что это будет делать):

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

Тогда когда либо onError или onSuccess возвращается в вашей подписке, и именно здесь вы сообщаете UI, что он готов к продолжению. Затем у вас будет действительный ответ или вы сможете показать ошибку пользователю.

РЕДАКТИРОВАТЬ: Реактивное программирование

После ваших комментариев кажется, что вы не понимаете реактивное программирование , У него немного крутая кривая обучения, и я все еще борюсь с ним сегодня.

Ваш APICaller класс, каким бы он ни был, должен возвращать сам Observable. Вы не должны передавать Fragment этому и обрабатывать его внутри, поскольку вы открываете себя утечкам памяти и ее небольшому запаху кода. Лучше всего просто вернуть Observable, возвращаемое mAPIService.getData(). Вот и все. В данный момент вы толкаете Observable в другой поток, используя Schedulers.io(), который говорит вашему основному потоку, продолжайте и не ждите меня. Затем вы возвращаетесь в этот поток, когда ответ отправляется с использованием кода .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());
                    }

                });

});

Я хотел бы порекомендовать вам посмотреть некоторые учебные пособия, немного почитать, и я также хотел бы отослать вас назад к моей точке зрения о Single s в начале

...