Daniel Wilson
Daniel Wilson

Reputation: 19824

Observe a basic custom event in RxJava

I've just began trying to learn RxJava / RxAndroid here and I am trying to validate a form. I used Kaushik Gopal's lovely example here and got my edit texts working with the combineLatest subscription nicely. Now I want to observe something else as part of the same subscription. I have a button to choose a date of birth which returns it's result in my Fragment's onActivityResult() function. What kind of observer do I need for that?

private Observable<CharSequence> mNameChangeObservable; //etc.
private Observable<Date> mDateChangeObservable;

OnCreateView():

mIDNumberChangeObservable = RxTextView.textChanges(mIDNumberEditText).skip(1);
mNameChangeObservable = RxTextView.textChanges(mNameEditText).skip(1);
mEmailChangeObservable = RxTextView.textChanges(mEmailEditText).skip(1);
mPasswordChangeObservable = RxTextView.textChanges(mPasswordEditText).skip(1);

//mDateChangeObservable = ???;

Subscription:

    private void combineLatestEvents() {
    mSubscription = Observable.combineLatest(mLLNumberChangeObservable,
            mNameChangeObservable,
            mEmailChangeObservable,
            mPasswordChangeObservable,
            mDateChangeObservable,
            new Func5<CharSequence, CharSequence, CharSequence, CharSequence, Date, Boolean>() {
                @Override
                public Boolean call(CharSequence newIDNumber,
                                    CharSequence newName,
                                    CharSequence newEmail,
                                    CharSequence newPassword,
                                    Date newDate) {

                    boolean idNumberValid = !isEmpty(newIDNumber) && newIDNumber.length() == 8;
                    if (!idNumberValid) {
                        mLLNumberEditText.setError("Invalid ID Number!");
                    }

                    boolean nameValid = !isEmpty(newName);
                    if (!nameValid) {
                        mNameEditText.setError("Invalid Name!");
                    }

                    boolean emailValid = !isEmpty(newEmail) &&
                            EMAIL_ADDRESS.matcher(newEmail).matches();
                    if (!emailValid) {
                        mEmailEditText.setError("Invalid Email!");
                    }

                    boolean passValid = !isEmpty(newPassword) && newPassword.length() >= 8;
                    if (!passValid) {
                        mPasswordEditText.setError("Invalid Password!");
                    }

                    //Validate Date

                    return idNumberValid && nameValid && emailValid && passValid;
                }
            })//
            .subscribe(new Observer<Boolean>() {
                @Override
                public void onCompleted() {
                }

                @Override
                public void onError(Throwable e) {
                }

                @Override
                public void onNext(Boolean formValid) {
                    if (formValid) {
                        mSubmitButton.setEnabled(true);
                    } else {
                        //Also print error here
                        mSubmitButton.setEnabled(false);
                    }
                }
            });
}

OnActivityResult:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode != Activity.RESULT_OK) return;
    if (requestCode == REQUEST_DATE) {
        mDate = (Date) data.getSerializableExtra(Constants.Extras.EXTRA_DATE);
        updateDobButtonText(mDate);

        //Somehow tell my subscription I have a new date
    }
}

Upvotes: 2

Views: 1034

Answers (2)

Daniel Wilson
Daniel Wilson

Reputation: 19824

Okay after a hell of a lot more Googling I've come to the conclusion that the normal way to hook in to lifecycle events would be to use Trello's RxLifeCycle library. However because I just want to fire a simple synchronous event and I know precisely when (during onActivityResult), this is the solution I have found:

(1) Create a Subject - in this case I think a PublishSubject is best because it's only one object that needs emitting.

private PublishSubject<Date> mDateSubject = PublishSubject.create();

(2) Convert it to an Observable which will listen for events on the main thread.

public Observable<Date> makeDateObservable() {
    return mDateSubject.observeOn(AndroidSchedulers.mainThread());
}

(3) Emit the object by calling next() on the subject when we have it:

mDateSubject.onNext(mDate);

Upvotes: 0

iagreen
iagreen

Reputation: 31996

You can follow your current pattern to get events from a button. Button is a subclass of TextView, so you can call RxTextView.textChanges() with a Button as a parameter. It will emit items when the button text changes. Specifically, if this line

updateDobButtonText(mDate);

calls Button.setText(), you should get the event on your subscriber.

Upvotes: 1

Related Questions