首页 > 解决方案 > 同步 MVP 和 RxJava NetworkCall 的问题

问题描述

这是我的应用程序中的流数据:

在视图中,如果我调用presenter.Method(),我得到了方法onClick。在演示者的这个方法中,我将调用传递给模型(模型有他自己的抽象层 -> 接口 modelHelper。它通过构造函数演示器中的匕首 2 注入)。

在模型中,我得到了网络调用的方法:

@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 架构中,模型层是否应该注入抽象演示者的实例并将其连接到模型,就像使用视图一样?如果不是,我应该如何将数据从模型发送到演示者?

  1. 我尝试通过 RxJava2 将演示者连接到模型,但同步出现问题。在模型中,我从以下位置创建 observable:
private List<Items> items = new ArrayList<>();

和getter方法:

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

在这里我创建了 observable:

    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();
                                }
                        )
        );


    }
}

当我单击按钮进行搜索时,我得到了第一个空响应,因为我在列表中观察到尚未更新(它通过方法网络调用得到更新)。如果我第二次按下按钮,那是我从 1 个请求中获得所需数据的时候。我应该如何从不同的类中链接这 2 个 RxJava 方法?

标签: androidrx-java2mvpandroid-mvp

解决方案


1. 在MVP架构中,Model层是否应该像view一样注入抽象presenter的实例并连接到model?

不,模型层不应直接访问视图或表示层。.observeOn(AndroidSchedulers.mainThread())另请注意,放入任何模型层实现都没有多大意义。

如果不是,我应该如何将数据从模型发送到演示者?

模型应该只响应演示者的查询。这可能是一个简单的函数调用。模型不需要持有 Presenter 实例来处理它。


2. ...我应该如何从不同的类中链接这 2 个 RxJava 方法?

考虑这个实现:

模型

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

主持人

// 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();
                            }
                    )
    );
}

如果您每个屏幕仅获取一次数据,上述实现应该就足够了。但是您提到了刷新按钮之类的东西。为此,您可以使用BehaviorSubjector BehaviorProcessor

主持人

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()返回一个 observable,它一次发出一个数组项。因此,它在这种情况下不是很有用。

  2. 似乎您有一个对象和一个包装该对象的可观察对象。如果你把这两个东西放在同一个地方,这通常是一个糟糕设计的标志。

    私有 Observable> itemsObservable; 私有列表项;

这不是使用 observable 的正确方法,而且违反了单一事实来源。一种可能的重构方法:

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);
}

推荐阅读