web-dev-qa-db-fra.com

Chambre avec RxJava2 - (fluide, peut-être, modèle de référentiel)

J'utilise Room pour la couche de base de données dans mon application et Retrofit pour les appels réseau - à la fois dans room et retrofit J'utilise RxJava2 (c'est mon premier projet avec rxjava, donc je suis encore assez novice dans ce domaine). Pour injecter des bases de données, des api, etc. J'utilise Dagger 2.

Je souhaite passer un appel réseau et ajouter une réponse du réseau à la base de données. Lorsqu'il n'est pas nécessaire de passer un autre appel réseau - je souhaite récupérer les données de la base de données. J'ai des problèmes avec l'utilisation de Maybe/Flowable dans le référentiel de ma chambre.

Voici Dao:

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

Voici mon référentiel:

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

}

Je lance d'abord l'application pour remplir la base de données uniquement avec un appel réseau

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

Et lorsque l'appel réseau a été exécuté, les données ont été ajoutées avec succès à la base de données - j'exécute à nouveau l'application avec uniquement des données de la base de données et elle a également réussi - les données ont été extraites de db.

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

Mais quand j'essaye maintenant de faire une chose pareille

return getCoinResultsFromDatabase.switchIfEmpty(getCoinResultsFromMemory));

Le problème est que chaque fois switchIfEmpty est exécuté et chaque fois que "getCoinResultsFromMemory ()" est exécuté (même si les données de la base de données sont disponibles).

Selon https://medium.com/google-developers/room-rxjava-acb0cd4f3757 J'ai lu que le Flowable quand il n'y a pas de données dans la base de données n'émettra rien et je devrais utiliser Maybe. Mais pourquoi getResultsFromMemory () renvoie vide même s'il y a des données dans la base de données? Comment dois-je utiliser exactement Peut-être dans ce scénario?

J'ai essayé de changer Flowable en Peut-être

Maybe<List<Coin>> getCoinResultsFromDatabase()

et faire quelque chose comme ça - pour accéder à la resutl de peut-être et vérifier là si la liste est vide ou non, mais je ne sais pas comment retourner flowable dans ce cas:

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??
}

Peut-être que je manque quelque chose et qu'il existe une solution meilleure et plus propre.

10

Il y a peu de problèmes avec votre code:

1. On dirait que dans la salle Flowable<List<Coin>> getAllCoins() renverra toujours une certaine valeur: soit une liste d'éléments soit une liste vide donc Maybe ne sera pas utile ici

Dans ce morceau de code

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

la getCoinResultsFromNetwork est appelée à droite lorsque vous appelez la méthode getCoinResults et non lorsque le flowable est vide (c'est simple Java appel de méthode)

Vous devez effectuer un appel différé. La solution finale peut ressembler à ceci

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