Je travaille sur la mise en réseau de mon application. J'ai donc décidé d'essayer Retrofit Square . Je vois qu'ils prennent en charge simpleCallback
@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);
et RxJava Observable
@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);
Les deux semblent assez similaires à première vue, mais quand il s'agit de la mise en œuvre, cela devient intéressant ...
Alors qu'avec une implémentation de rappel simple, cela ressemblerait à ceci:
api.getUserPhoto(photoId, new Callback<Photo>() {
@Override
public void onSuccess() {
}
});
ce qui est assez simple et direct. Et avec Observable
cela devient rapidement verbeux et assez compliqué.
public Observable<Photo> getUserPhoto(final int photoId) {
return Observable.create(new Observable.OnSubscribeFunc<Photo>() {
@Override
public Subscription onSubscribe(Observer<? super Photo> observer) {
try {
observer.onNext(api.getUserPhoto(photoId));
observer.onCompleted();
} catch (Exception e) {
observer.onError(e);
}
return Subscriptions.empty();
}
}).subscribeOn(Schedulers.threadPoolForIO());
}
Et ce n'est pas ça. Vous devez encore faire quelque chose comme ça:
Observable.from(photoIdArray)
.mapMany(new Func1<String, Observable<Photo>>() {
@Override
public Observable<Photo> call(Integer s) {
return getUserPhoto(s);
}
})
.subscribeOn(Schedulers.threadPoolForIO())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Photo>() {
@Override
public void call(Photo photo) {
//save photo?
}
});
Est-ce que j'ai râté quelque chose? Ou est-ce un mauvais cas pour utiliser Observable
s? Quand préfèrerait-on / devrait-on préférer un Observable
simple rappel?
Mettre à jour
L'utilisation de retrofit est beaucoup plus simple que l'exemple ci-dessus comme @Niels l'a montré dans sa réponse ou dans l'exemple de projet U2020 de Jake Wharton . Mais la question reste essentiellement la même: quand utiliser l'un ou l'autre?
Réponses:
Pour les choses de réseautage simples, les avantages de RxJava par rapport à Callback sont très limités. Le simple exemple getUserPhoto:
RxJava:
Rappeler:
La variante RxJava n'est pas beaucoup mieux que la variante Callback. Pour l'instant, ignorons la gestion des erreurs. Prenons une liste de photos:
RxJava:
Rappeler:
Maintenant, la variante RxJava n'est toujours pas plus petite, bien qu'avec Lambdas, elle serait plus proche de la variante Callback. De plus, si vous avez accès au flux JSON, il serait assez étrange de récupérer toutes les photos lorsque vous n'affichez que les fichiers PNG. Ajustez simplement le flux pour qu'il affiche uniquement les fichiers PNG.
Première conclusion
Cela ne rend pas votre base de code plus petite lorsque vous chargez un simple JSON que vous avez préparé pour être au bon format.
Maintenant, rendons les choses un peu plus intéressantes. Supposons que vous souhaitiez non seulement récupérer la photo utilisateur, mais que vous ayez un clone Instagram et que vous souhaitiez récupérer 2 JSON: 1. getUserDetails () 2. getUserPhotos ()
Vous souhaitez charger ces deux JSON en parallèle, et lorsque les deux sont chargés, la page doit être affichée. La variante de rappel deviendra un peu plus difficile: vous devez créer 2 rappels, stocker les données dans l'activité, et si toutes les données sont chargées, afficher la page:
Rappeler:
RxJava:
Nous arrivons quelque part! Le code de RxJava est maintenant aussi gros que l'option de rappel. Le code RxJava est plus robuste; Pensez à ce qui se passerait si nous avions besoin d'un troisième JSON à charger (comme les dernières vidéos)? Le RxJava n'aurait besoin que d'un petit ajustement, tandis que la variante de rappel doit être ajustée à plusieurs endroits (à chaque rappel, nous devons vérifier si toutes les données sont récupérées).
Un autre exemple; nous voulons créer un champ de saisie semi-automatique, qui charge les données à l'aide de Retrofit. Nous ne voulons pas faire un appel Web chaque fois qu'un EditText a un TextChangedEvent. Lorsque vous tapez rapidement, seul le dernier élément doit déclencher l'appel. Sur RxJava, nous pouvons utiliser l'opérateur anti-rebond:
Je ne vais pas créer la variante Callback mais vous comprendrez que c'est beaucoup plus de travail.
Conclusion: RxJava est exceptionnellement bon lorsque les données sont envoyées sous forme de flux. Le Retrofit Observable pousse tous les éléments du flux en même temps. Ce n'est pas particulièrement utile en soi par rapport à Callback. Mais quand il y a plusieurs éléments poussés sur le flux et à différents moments, et que vous devez faire des choses liées au timing, RxJava rend le code beaucoup plus maintenable.
la source
inputObservable
? J'ai beaucoup de problèmes avec le rebond et j'aimerais en savoir un peu plus sur cette solution.RxView
,RxTextView
etc. qui peuvent être utilisées pour leinputObservable
.Le truc observable est déjà fait dans Retrofit, donc le code pourrait être le suivant:
la source
Callback
vous pouvez vous désinscrireObserveable
, évitant ainsi les problèmes de cycle de vie courants.Dans le cas de getUserPhoto (), les avantages de RxJava ne sont pas importants. Mais prenons un autre exemple lorsque vous obtiendrez toutes les photos d'un utilisateur, mais uniquement lorsque l'image est au format PNG et que vous n'avez pas accès au JSON pour effectuer le filtrage côté serveur.
Maintenant, le JSON retourne une liste de photos. Nous allons les mapper à des éléments individuels. Ce faisant, nous pourrons utiliser la méthode de filtrage pour ignorer les photos qui ne sont pas PNG. Après cela, nous nous abonnerons et recevrons un rappel pour chaque photo individuelle, un gestionnaire d'erreur et un rappel lorsque toutes les lignes seront terminées.
TLDR Point ici étant; le rappel ne vous renvoie qu'un rappel de réussite et d'échec; l'Observable RxJava vous permet de cartographier, réduire, filtrer et bien d'autres choses.
la source
Avec rxjava, vous pouvez faire plus de choses avec moins de code.
Supposons que vous souhaitiez implémenter la recherche instantanée dans votre application. Avec les rappels, vous vous inquiétez de vous désabonner de la demande précédente et de vous abonner à la nouvelle, de gérer vous-même le changement d'orientation ... Je pense que c'est beaucoup de code et trop verbeux.
Avec rxjava, c'est très simple.
si vous voulez implémenter la recherche instantanée, il vous suffit d'écouter TextChangeListener et d'appeler
photoModel.setUserId(EditText.getText());
Dans la méthode onCreate de Fragment ou d'activité, vous vous abonnez à l'Observable qui renvoie photoModel.subscribeToPhoto (), il retourne un Observable qui émet toujours les éléments émis par le dernier Observable (demande).
De plus, si PhotoModel est un Singleton, par exemple, vous n'avez pas à vous soucier des changements d'orientation, car BehaviorSubject émet la dernière réponse du serveur, quel que soit le moment de votre abonnement.
Avec ces lignes de code, nous avons implémenté une recherche instantanée et géré les changements d'orientation. Pensez-vous que vous pouvez implémenter cela avec des rappels avec moins de code? J'en doute.
la source
Nous suivons généralement la logique suivante:
la source
D'après les échantillons et les conclusions des autres réponses, je pense qu'il n'y a pas de grande différence pour les tâches simples en une ou deux étapes. Cependant, le rappel est simple et direct. RxJava est plus compliqué et trop grand pour une tâche simple. Il y a la troisième solution par: AbacusUtil . Permettez-moi d'implémenter les cas d'utilisation ci-dessus avec les trois solutions: Callback, RxJava, CompletableFuture (AbacusUtil) avec Retrolambda :
Récupérer la photo du réseau et enregistrer / afficher sur l'appareil:
Charger les détails de l'utilisateur et la photo en parallèle
la source
Personnellement, je préfère utiliser Rx pour obtenir des réponses api dans les cas où je dois filtrer, mapper ou quelque chose comme ça sur les données Ou dans les cas où je dois faire un autre appel api en fonction des réponses aux appels précédents
la source
Il semble que vous réinventiez la roue, ce que vous faites est déjà implémenté dans la rénovation.
Par exemple, vous pouvez regarder RestAdapterTest.java de retrofit , où ils définissent une interface avec Observable comme type de retour, puis l' utiliser .
la source
Lorsque vous créez une application pour le plaisir, un projet pour animaux de compagnie ou un POC ou le 1er prototype, vous utilisez des classes Android / Java simples comme les rappels, les tâches asynchrones, les boucles, les threads, etc. Elles sont simples à utiliser et ne nécessitent aucune Intégration de bibliothèques tierces. Une grande intégration de bibliothèque juste pour construire un petit projet immuable est illogique quand quelque chose de similaire peut être fait dès le départ.
Cependant, ce sont comme un couteau très tranchant. Les utiliser dans un environnement de production est toujours cool, mais cela aura aussi des conséquences. Il est difficile d'écrire du code simultané sûr si vous n'êtes pas bien familiarisé avec le codage propre et les principes SOLIDES. Vous devrez maintenir une architecture appropriée pour faciliter les changements futurs et améliorer la productivité de l'équipe.
D'autre part, les bibliothèques de concurrence comme RxJava, Co-routines, etc. sont essayées et testées plus d'un milliard de fois pour aider à écrire du code concurrent prêt pour la production. Encore une fois, ce n'est pas qu'en utilisant ces bibliothèques, vous n'écrivez pas de code simultané ou n'abstenez pas toute la logique de concurrence. Vous l'êtes toujours. Mais maintenant, il est visible et applique un modèle clair pour l'écriture de code simultané dans toute la base de code et, plus important encore, dans votre équipe de développement.
Il s'agit d'un avantage majeur de l'utilisation d'un cadre de concurrence au lieu des anciennes classes de base simples qui traitent de la concurrence brute. Cependant, ne vous méprenez pas. Je suis un grand partisan de la limitation des dépendances de la bibliothèque externe, mais dans ce cas spécifique, vous devrez créer un cadre personnalisé pour votre base de code qui est une tâche longue et ne peut être effectuée qu'après une expérience préalable. Par conséquent, les cadres de concurrence sont préférés à l'utilisation de classes simples comme les rappels, etc.
TL'DR
Si vous utilisez déjà RxJava pour le codage simultané dans toute la base de code, utilisez simplement RxJava Observable / Flowable. Une sage question à poser est alors de savoir si j'utilise Observables à Flowables. Sinon, allez-y et utilisez un appelable.
la source