web-dev-qa-db-ja.com

RxJava2のある部屋-(Flowable、たぶん、リポジトリパターン)

私は、アプリケーションのデータベースレイヤーにRoomを使用し、ネットワークコールにRetrofitを使用しています-部屋とレトロフィットの両方でRxJava2を使用しています(これはrxjavaを使用した最初のプロジェクトなので、この分野ではまだまだ初心者です)。データベース、APIなどを注入するには、Dagger 2を使用しています。

ネットワークコールを作成し、ネットワークからデータベースに応答を追加したいと思います。別のネットワーク呼び出しを行う必要がない場合-データベースからデータをフェッチしたい。部屋のリポジトリでMaybe/Flowableを使用することに問題があります。

これはダオです:

@Dao
public interface CoinDao {
    @Query("SELECT * FROM coin")
    Flowable<List<Coin>> getAllCoins();

    @Insert
    void insert(List<Coin> coins);

    @Update
    void update(Coin... coins);

    @Delete
    void delete(Coin... coins);
}

これは私のリポジトリです:

public class CoinRepository implements Repository {

private CoinMarketCapNetworkApi api;

private final CoinDao coinDao;


public CoinRepository(CoinMarketCapNetworkApi api, CoinDao coinDao) {
    System.out.println("Creating CoinRepository");
    this.api = api;
    this.coinDao = coinDao;
}

@Override
public Flowable<List<Coin>> getCoinResults() {
    System.out.println("getting coin results");
    return getCoinResultsFromDatabase().switchIfEmpty(getCoinResultsFromNetwork())
}


@Override
public Flowable<List<Coin>> getCoinResultsFromNetwork() {
    System.out.println("getting results from network");
    return api.getCoins().doOnNext(new Consumer<List<Coin>>() {
        @Override
        public void accept(List<Coin> coins) throws Exception {
            System.out.println("inserting to db");
            coinDao.insert(coins);
        }
    });
}

@Override
public Flowable<List<Coin>> getCoinResultsFromDatabase() {
    System.out.println("getting coins from database");
    return coinDao.getAllCoins();
}

}

最初にアプリを実行して、ネットワーク呼び出しのみでデータベースを埋めます

@Override
public Flowable<List<Coin>> getCoinResults() {
return getCoinResultsFromNetwork();
}

そして、ネットワークコールが実行されたとき、データはデータベースに正常に追加されました-データベースからデータを取得するだけでアプリをもう一度実行し、それも成功しました-データはデータベースからフェッチされました。

@Override
public Flowable<List<Coin>> getCoinResults() {
return getCoinResultsFromDatabase();
}

でも今こういうことをやろうとすると

return getCoinResultsFromDatabase.switchIfEmpty(getCoinResultsFromMemory));

問題は、switchIfEmptyが実行されるたび、および「getCoinResultsFromMemory()」が実行されるたびに(データベース内のデータが利用可能であっても)です。

https://medium.com/google-developers/room-rxjava-acb0cd4f3757 によると、データベースにデータがない場合のFlowableは何も出力せず、Maybeを使用する必要があると読みました。しかし、データベースにデータがあるにもかかわらずgetResultsFromMemory()が空を返すのはなぜですか?このシナリオでは、Maybeをどの程度正確に使用する必要がありますか?

FlowableをMaybeに変更してみました

Maybe<List<Coin>> getCoinResultsFromDatabase()

そして、このようなことをします-多分から結果にアクセスし、リストが空かどうかを確認するために、この場合、flowableを返す方法がわかりません:

public Flowable<List<Coin>> getCoinResults() {
getCoinResultsFromDatabase().subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer<List<Coin>>() {
                @Override
                public void accept(List<Coin> coins) throws Exception {
                    System.out.println("returning coins from maybe" + coins.get(0).getId());
                    if (coins.isEmpty()) {
                        System.out.println("coin list is empty");
                        Flowable<List<Coin>> flowable = getCoinResultsFromNetwork();
                    } else {
                         Flowable<List<Coin>> flowable = getCoinResultsFromDatabase();
                    }
                }
            });
return flowable //how to access this flowable??
}

多分私は何かが欠けており、より良い、よりクリーンな解決策があります。

10

コードにはいくつかの問題があります:

1.部屋のように見えるFlowable<List<Coin>> getAllCoins()は常にいくつかの値を返します:アイテムのリストまたは空のリストのどちらかなので、Maybeはここでは役に立ちません

2.このコードで

@Override
public Flowable<List<Coin>> getCoinResults() {
    System.out.println("getting coin results");
    return getCoinResultsFromDatabase().switchIfEmpty(getCoinResultsFromNetwork())
}

getCoinResultsFromNetworkは、getCoinResultsメソッドを呼び出したときに正しく呼び出されます。これは、フロー可能変数が空のときではありません(これは単純なJavaメソッド呼び出しです)

遅延呼び出しを実行する必要があります。最終的なソリューションは次のようになります

@Override
public Flowable<List<Coin>> getCoinResults() {
    System.out.println("getting coin results");
    return getCoinResultsFromDatabase()
        .filter(list -> !list.isEmpty())
        .switchIfEmpty(
            Flowable.defer(() -> getCoinResultsFromNetwork()))
}
4
httpdispatch