web-dev-qa-db-fra.com

Remplacer les rappels par des observables de RxJava

J'utilise des écouteurs comme des rappels pour observer les opérations asynchrones avec Android, mais je pense que cela pourrait être génial de remplacer ces écouteurs par RxJava, je suis un nouvel utilisateur de cette bibliothèque mais je l'aime vraiment beaucoup et je l'utilise toujours avec des projets Android.

Voici mon code pour refactor:

public void getData( final OnResponseListener listener ){
   if(data!=null && !data.isEmpty()){
       listener.onSuccess();
   }
   else{
       listener.onError();
   }
}

Un simple rappel:

public interface OnResponseListener {
   public void onSuccess();
   public void onError(); 
}

Et l'observateur:

object.getData( new OnResponseListener() {
    @Override
    public void onSuccess() {
       Log.w(TAG," on success");
    }

    @Override
    public void onError() {
       Log.e(TAG," on error");
    }
});

Merci!

13
Pablo Cegarra

Par exemple, vous pouvez utiliser Observable.fromCallable pour créer observable avec vos données.

public Observable<Data> getData(){
    return Observable.fromCallable(() -> {
        Data result = null;
        //do something, get your Data object
        return result;
    });
}

puis utilisez vos données 

 getData().subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(data -> {
                //do something with your data
            }, error -> {
                //do something on error
            });

Utilisé les expressions rxjava 1.x et lambda.

modifier:

si je vous ai bien compris, vous vouliez remplacer cet auditeur et non le rendre visible. J'ai ajouté un autre exemple en référence à votre commentaire. Oh .. vous devriez aussi utiliser Single si vous attendez un seul article. 

public Single<Data> getData() {
        return Single.create(singleSubscriber -> {
            Data result = object.getData();
            if(result == null){
                singleSubscriber.onError(new Exception("no data"));
            } else {
                singleSubscriber.onSuccess(result);
            }
        });
    }

getData().subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(data -> {
                //do something with your data
            }, error -> {
                //do something on error
            });
12
YMY

Vous recherchez Completable.create:

Completable: représente un calcul différé sans aucune valeur, mais uniquement une indication de fin ou d'exception. La classe suit un modèle d’événement similaire à Reactive-Streams: onSubscribe (onError | onComplete)?

Completable.create(subscriber -> {
    object.getData(new OnResponseListener() {
        @Override
        public void onSuccess() {
           subscriber.onCompleted();
        }

        @Override
        public void onError() {
           subscriber.onError(* put appropriate Throwable here *);
        }
    }
})
...//apply Schedulers
.subscribe((() -> *success*), (throwable -> *error*));
5
Maksim Ostrovidov

Comment je refactoriser votre code; à côté de la méthode getData, j'ajouterais la méthode getData enveloppée en tant que Single:

public void getData( final OnResponseListener listener ){
    if(data!=null && !data.isEmpty()){
        listener.onSuccess();
    }
    else{
        listener.onError();
    }
}

public Single<Boolean> getDataSingle() {
    return Single.create(new SingleOnSubscribe<Boolean>() {
        @Override
        public void subscribe(SingleEmitter<Boolean> e) throws Exception {
            getData(new OnResponseListener() {
                @Override
                public void onSuccess() {
                    e.onSuccess(true);
                }

                @Override
                public void onError() {
                    e.onSuccess(false);
                }
            });
        }
    });
}

Ou avec Java 8:

public Single<Boolean> getDataSingle() {
    return Single.create(e -> getData(
            new OnResponseListener() {
                @Override
                public void onSuccess() {
                    e.onSuccess(true);
                }

                @Override
                public void onError() {
                    e.onSuccess(false);
                }
            })
    );
}

Vous avez maintenant exposé une API Rx à côté de celle du rappel. En supposant qu'il s'agisse d'une sorte de fournisseur de données, vous pouvez maintenant l'utiliser sans traiter les rappels, comme ceci:

dataProvider.getDataSingle()
        .map(result -> result ? "User exist" : "User doesn't exist")
        .subscribe(message -> display(message));

J'ai utilisé Rx2 mais avec Rx1 la logique est la même.

J'ai également utilisé un Single au lieu d'un observable, car vous n'attendez qu'une seule valeur. L'intérêt est un contrat plus expressif pour votre fonction. 

Vous ne pouvez pas émettre de valeur au nom d'un observable, c'est-à-dire appeler quelque chose comme myObservable.send (value). La première solution consiste à utiliser un Subject . Une autre solution (celle ci-dessus) consiste à créer l'observable avec Observable.create () (ou Single.create ()). Vous appelez la méthode de rappel et créez l'écouteur dans la méthode Observable.create (), car c'est dans Observable.create () que vous pouvez appeler la méthode onSuccess (), méthode qui a demandé à Observable de transmettre une valeur.

C'est ce que j'utilise pour transformer le rappel en observable. Un peu compliqué au début, mais facile à adapter.

Je vous donne un autre exemple, comme demandé. Supposons que vous souhaitiez afficher les modifications d'un EditText en tant que barre de progression:

View rootView;
EditText editTextView;

//Wrap Android addTextChangedListener into an Observable
Observable<String> textObservable = Observable.create(consumer ->
        editTextView.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                consumer.onNext(s.toString());
            }
        })
);

//Use it
textObservable.subscribe(text -> Snackbar.make(rootView, text, Snackbar.LENGTH_SHORT).show());
3
Geoffrey Marizy
Maybe.<String>create(new MaybeOnSubscribe<String>() {
      @Override
      public void subscribe(MaybeEmitter<String> e) throws Exception {
        OnSuccessListener(uri->{
          e.onSuccess(uri));
        })
        .addOnFailureListener(throwable -> {
          e.onError(throwable);
        });
      }
    });
0
Amjed Baig