kunny / RxFirebase

RxJava binding APIs for Firebase.
Apache License 2.0
139 stars 25 forks source link

Consider a Children Ready Event #1

Closed bnvinay92 closed 8 years ago

bnvinay92 commented 8 years ago

It's tough to show empty states and handle other ui logic when you use Firebase's ChildEventListener as is. I like to add a value event listener which fires after all your current data has been loaded. Something like this:

public static Observable<FirebaseChildEvent> children(Query query) {
        return Observable.fromEmitter(new Action1<AsyncEmitter<FirebaseChildEvent>>() {
            @Override public void call(AsyncEmitter<FirebaseChildEvent> emitter) {
                ChildEventListener listener = new ChildEventListener() {
                    @Override public void onChildAdded(DataSnapshot dataSnapshot, String previousKey) {
                        emitter.onNext(create(dataSnapshot, ADDED, previousKey));
                    }

                    @Override public void onChildChanged(DataSnapshot dataSnapshot, String previousKey) {
                        emitter.onNext(create(dataSnapshot, CHANGED, previousKey));
                    }

                    @Override public void onChildRemoved(DataSnapshot dataSnapshot) {
                        emitter.onNext(create(dataSnapshot, REMOVED, null));
                    }

                    @Override public void onChildMoved(DataSnapshot dataSnapshot, String previousKey) {
                        emitter.onNext(create(dataSnapshot, MOVED, previousKey));
                    }

                    @Override public void onCancelled(DatabaseError databaseError) {
                        emitter.onError(databaseError.toException());
                    }
                };
                ValueEventListener readyListener = new ValueEventListener() {
                    @Override public void onDataChange(DataSnapshot dataSnapshot) {
                        emitter.onNext(create(dataSnapshot, READY, null));
                    }

                    @Override public void onCancelled(DatabaseError databaseError) {
                        emitter.onError(databaseError.toException());
                    }
                };
                emitter.setCancellation(new AsyncEmitter.Cancellable() {
                    @Override public void cancel() throws Exception {
                        query.removeEventListener(listener);
                        query.removeEventListener(readyListener);
                    }
                });
                query.addChildEventListener(listener);
                query.addListenerForSingleValueEvent(readyListener);
            }
        }, AsyncEmitter.BackpressureMode.BUFFER);
    }

Firebase's internal optimisation makes sure that the data on your reference only comes through the wire once.

kunny commented 8 years ago

Since this library aims to wrap Firebase Android SDK into Rx, custom behavior (like ChildReadyEvent) will not be added.

Instead, I can add a support for Query to methods in RxFirebaseDatabase.

After then, you can use it as follows:

Query query = ...;

//TODO: Show progress while Firebase loads data

RxFirebaseDatabase.data(query)
    .observeOn(AndroidSchedulers.mainThread()) // For Android
    .doOnError {  /* TODO: Hide progress */  }
    .doOnCompleted { /* TODO: Hide progress */ }
    .subscribe()
kunny commented 8 years ago

@bnvinay92 I have found following method in SDK, Query.getRef()

With this method, I expect you can achieve what you want with current library by implementing as following:

Query query = ...;

//TODO: Show progress while Firebase loads data

RxFirebaseDatabase.data(query.getRef())
    .observeOn(AndroidSchedulers.mainThread()) // For Android
    .doOnError {  /* TODO: Hide progress */  }
    .doOnCompleted { /* TODO: Hide progress */ }
    .subscribe()