Проблема с синхронизацией MVP и RxJava NetworkCall - PullRequest
0 голосов
/ 20 февраля 2019

Вот данные потока в моем приложении:

В связи с этим я получил метод onClick, где я вызываю Presenter.Method ().В этом методе на Presenter я передаю вызов модели (Model получил свой собственный уровень абстракции -> interface modelHelper. Он вводится через кинжал 2 в Conctructor Presenter).

В модели у меня есть метод для сетевого вызова:

@Override
   public void networkCallForData(String request) {
       request = "volumes?q=" + request;
       compositeDisposable.add(
               api.getBook(request)
                       .subscribeOn(Schedulers.io())
                       .observeOn(AndroidSchedulers.mainThread())
                       .subscribe(
                               books -> {
                                   items.clear();
                                   items.addAll(books.items);

                               }
                               , Throwable::printStackTrace
                               , () -> {
                               }
                       )
       );
   }
}

У меня есть 2 вопроса: 1. В архитектуре MVP должен ли слой модели внедрить экземпляр абстрагированного презентатора и подключить его к модели так же, какс видом?если нет, то как мне отправить данные от модели докладчику?

Я пытаюсь подключить докладчик к модели через RxJava2, но возникла проблема с синхронизацией.В модели я создаю наблюдаемый из:
private List<Items> items = new ArrayList<>();

и метод получения к нему:

 public Observable<List<Items>> getItemsObservable() {
        return itemsObservable;
    }

здесь я создаю наблюдаемый:

    private Observable<List<Items>> itemsObservable = Observable.fromArray(items);

В докладчикея получил:

 private void getDataFromModel() {

        compositeDisposable.add(
                findActivityModel.getItemsObservable()
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(
                                books -> {
                                       view.setRecycler(books);

                                }, Throwable::printStackTrace
                                , () -> {

                                    view.setRecyclerVisible();
                                }
                        )
        );


    }
}

Когда я нажимаю на кнопку для поиска, я получаю первый пустой ответ, потому что наблюдаю в списке с еще не обновленным (он обновляется через сетевой вызов метода).Если я нажму кнопку 2 раза, то получу данные из 1 запроса.Как я должен связать эти 2 метода RxJava из другого класса?

1 Ответ

0 голосов
/ 22 февраля 2019

1.В архитектуре MVP, должен ли слой Model внедрить экземпляр абстрагированного презентатора и подключить его к модели, как в представлении?

Нет.Слой модели не должен иметь прямого доступа к слою просмотра или представления.Также обратите внимание, что не имеет смысла помещать .observeOn(AndroidSchedulers.mainThread()) в любую реализацию уровня модели.

, если нет, то как я должен отправлять данные из модели в презентатор?

Модель должна просто отвечать на запросы докладчиков.Это может быть простой вызов функции.Для обработки модели не требуется хранить экземпляры Presenter.


2.... Как мне связать эти два метода RxJava из другого класса?

Рассмотрим эту реализацию:

Модель

@Override
public Observable<List<Items>> networkCallForData(String request) {
    request = "volumes?q=" + request;
    return api.getBook(request);
}

Presenter

// Call this once in the beginning.
private void getDataFromModel() {

    compositeDisposable.add(
            findActivityModel.networkCallForData(request)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(
                            books -> {
                                   view.setRecycler(books);
                            }, Throwable::printStackTrace
                            , () -> {
                                view.setRecyclerVisible();
                            }
                    )
    );
}

Вышеприведенной реализации должно быть достаточно, если вы получаете данные только один раз за экран.Но вы упомянули что-то вроде кнопки обновления.Для этого вы можете использовать BehaviorSubject или BehaviorProcessor.

Presenter

private BehaviorSubject<List<Item>> items =
    BehaviorSubject.create(); // You may move this line to the Model layer.

// Call this once in the beginning to setup the recycler view.
private void getDataFromModel() {
    // Instead of subscribing to Model, subscribe to BehaviorSubject.
    compositeDisposable.add(
            items.subscribe(books -> {
                   // Any change in BehaviorSubject should be notified
                   view.setRecycler(books);
                   view.setRecyclerVisible();
            });
}


// Trigger this on button clicks
private void refreshData() {
    compositeDisposable.add(
            findActivityModel.networkCallForData(request)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(books -> {
                        // Refresh BehaviorSubject
                        items.onNext(books);
                    });
}

Даже это может не совсем соответствовать вашим потребностям, но надеюсь, что вы получитеидея.Кроме того, несколько примечаний:

  1. Observable.fromArray() возвращает наблюдаемое, которое испускает элементы массива по одному за раз.Поэтому в этом сценарии это не очень полезно.

  2. Кажется, у вас есть объект и наблюдаемое, которое оборачивает объект.Если эти две вещи находятся в одном и том же месте, это обычно является признаком плохого дизайна.

    private Observable> itemsObservable;приватные элементы списка;

Это неправильный способ использовать наблюдаемые, но также нарушает единый источник правды.Один из возможных способов рефакторинга это:

private BehaviorSubject<List<Items>> itemsObservable;
// private List<Items> items; // Remove this line

public Observable<List<Items>> getItemsObservable() {
    return itemsObservable.hide();
}

// Call this whenever you need to update itemsObservable
private void updateItems(List<Item> newItems) {
    itemsObservable.onNext(newItems);
}
...