Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Firebase and RxJava

Firebase and RxJava

In Ezhome we are using Firebase because we need to support our users to continue their work even without network connection. We created an RxJava Firebase implementation in order to be used based on our clean architecture approach.

In the presentation we will discuss which are the pros and cons of using Firebase in a production environment and which are the problems which you are going to face and how to eliminate them in an effective way.

In the same presentation we will present the RxFirebase library and the usage on top of firebase and how you can effective use it in a clean architecture approach.

The presentation took place at Droidcon Greece 2016 at Thessaloniki. http://2016.droidcon.gr/agenda/

The presentation took place at 1st Athens Android Developer meetup in Greece. https://www.meetup.com/Athens-Android-Developers-Group/events/233817302/

Spiros Economakis

July 11, 2016
Tweet

More Decks by Spiros Economakis

Other Decks in Programming

Transcript

  1. ezhome is a new breed of gardening company that’s revolutionizing

    the way gardening is done. We’re using technology to help gardeners with their work, enable better communication, and vastly improve the customer experience.
  2. Firebase Database • Cloud-hosted NoSQL database • Real-time - Non

    HTTP • Data stored as JSON • Offline • Accessible by different devices • Security rules • Multiple Authentication Providers
  3. Plan Data Structure Need to take care how the data:

    • is going to be saved • is going to be retrieved { "users": { "alovelace": { "name": "Ada Lovelace", "contacts": { "ghopper": true }, }, "ghopper": { }, "eclarke": { } } }
  4. Plan Nested Data Structure NoSQL databases does not allow JOINS.

    The solution is to use embedded data with nested data structure. Firebase allows nesting data up to 32 levels deep { "chats": { "one": { "title": "Historical Tech Pioneers", "messages": { "m1": { "sender": "ghopper", "message": "Test text." }, "m2": { }, } }, "two": { } } }
  5. Avoid nesting data When you fetch data at a location

    in firebase, you also retrieve all of its child nodes. Example I want show the conversation titles from chats: databaseReference.child("chats");
  6. More... Fatal Exception: java.lang.RuntimeException: Uncaught exception in Firebase runloop. Please

    report to [email protected] at com.firebase.client.android.AndroidPlatform$1$1.run(AndroidPlatform.java:59) at android.os.Handler.handleCallback(Handler.java:733) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5057) at java.lang.reflect.Method.invokeNative(Method.java) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602) at dalvik.system.NativeStart.main(NativeStart.java)
  7. Flatten data structure FTW { "chats": { "one": { "title":

    "Historical Tech Pioneers", "lastMessage": "ghopper: Relay malfunction found. Cause: moth.", "timestamp": 1459361875666 }, "two": {}, "three": {} } } { "members": { "one": { "ghopper": true, "alovelace": true, "eclarke": true }, "two": { }, "three": { } } }
  8. More... { "messages": { "one": { "m1": { "name": "eclarke",

    "message": "The relay seems to be malfunctioning.", "timestamp": 1459361875337 }, "m2": { ... }, "m3": { ... } }, "two": { ... }, "three": { ... } } }
  9. Firebase usage FirebaseDatabase.getInstance().setPersistenceEnabled(true); DatabaseReference postsRef = FirebaseDatabase.getInstance().getReference("posts"); ValueEventListener postListener =

    new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // Get Post object and use the values to update the UI Post post = dataSnapshot.getValue(Post.class); } @Override public void onCancelled(DatabaseError databaseError) { // Getting Post failed, log a message Log.w(TAG, "loadPost:onCancelled", databaseError.toException()); } }; postsRef.addValueEventListener(postListener);
  10. Keep in mind... • Synchronizes and stores a local copy

    of the data for active listeners • You can keep the data fresh even if the reference has no active listeners (but be careful) DatabaseReference postsRef = FirebaseDatabase.getInstance().getReference("posts"); postsRef.keepSynced(true);
  11. RxFirebase by ezhome RxJava wrapper on top of Firebase. The

    library includes: • RxFirebaseAuth • RxFirebaseDatabase https://github.com/ezhome/Android-RxFirebase
  12. RxFirebaseAuth //Observes sign-in in Firebase with Auth Providers Observable<FirebaseUser> observeSignIn(final

    AuthCredential authCredential); //Observes sign-in in Firebase with Custom token Observable<FirebaseUser> observeSignIn(final String token); //Observes the sign-out Observable<Boolean> observeSignOut(); //Observes the authentication state Observable<FirebaseUser> observeAuthState();
  13. //Observes sign-in in Firebase with Auth Providers Observable<FirebaseUser> observeSignIn(final AuthCredential

    authCredential); //Observes sign-in in Firebase with Custom token Observable<FirebaseUser> observeSignIn(final String token); //Observes the sign-out Observable<Boolean> observeSignOut(); //Observes the authentication state Observable<FirebaseUser> observeAuthState(); RxFirebaseAuth
  14. //Observes sign-in in Firebase with Auth Providers Observable<FirebaseUser> observeSignIn(final AuthCredential

    authCredential); //Observes sign-in in Firebase with Custom token Observable<FirebaseUser> observeSignIn(final String token); //Observes the sign-out Observable<Boolean> observeSignOut(); //Observes the authentication state Observable<FirebaseUser> observeAuthState(); RxFirebaseAuth
  15. //Observes sign-in in Firebase with Auth Providers Observable<FirebaseUser> observeSignIn(final AuthCredential

    authCredential); //Observes sign-in in Firebase with Custom token Observable<FirebaseUser> observeSignIn(final String token); //Observes the sign-out Observable<Boolean> observeSignOut(); //Observes the authentication state Observable<FirebaseUser> observeAuthState(); RxFirebaseAuth
  16. //Observes sign-in in Firebase with Auth Providers Observable<FirebaseUser> observeSignIn(final AuthCredential

    authCredential); //Observes sign-in in Firebase with Custom token Observable<FirebaseUser> observeSignIn(final String token); //Observes the sign-out Observable<Boolean> observeSignOut(); //Observes the authentication state Observable<FirebaseUser> observeAuthState(); RxFirebaseAuth
  17. //Observes saving data and returns the generated key Observable<String> observeValuePush(final

    DatabaseReference firebaseRef, final Object object); //Observes retrieve data and emits when data changed in a specific Firebase Query Observable<DataSnapshot> observeValueEvent(final Query firebaseRef); //Observes new additions in a specific Firebase Query Observable<FirebaseChildEvent> observeChildAdded(final Query firebaseRef); more……. RxFirebaseDatabase
  18. //Observes saving data and returns the generated key Observable<String> observeValuePush(final

    DatabaseReference firebaseRef, final Object object); //Observes retrieve data and emits when data changed in a specific Firebase Query Observable<DataSnapshot> observeValueEvent(final Query firebaseRef); //Observes new additions in a specific Firebase Query Observable<FirebaseChildEvent> observeChildAdded(final Query firebaseRef); more……. RxFirebaseDatabase
  19. //Observes saving data and returns the generated key Observable<String> observeValuePush(final

    DatabaseReference firebaseRef, final Object object); //Observes retrieve data and emits when data changed in a specific Firebase Query Observable<DataSnapshot> observeValueEvent(final Query firebaseRef); //Observes new additions in a specific Firebase Query Observable<FirebaseChildEvent> observeChildAdded(final Query firebaseRef); more……. RxFirebaseDatabase
  20. //Observes saving data and returns the generated key Observable<String> observeValuePush(final

    DatabaseReference firebaseRef, final Object object); //Observes retrieve data and emits when data changed in a specific Firebase Query Observable<DataSnapshot> observeValueEvent(final Query firebaseRef); //Observes new additions in a specific Firebase Query Observable<FirebaseChildEvent> observeChildAdded(final Query firebaseRef); more……. RxFirebaseDatabase
  21. RxFirebaseDatabase public Observable<DataSnapshot> observeValueEvent(final Query firebaseRef) { return Observable.create(new Observable.OnSubscribe<DataSnapshot>()

    { @Override public void call(final Subscriber<? super DataSnapshot> subscriber) { final ValueEventListener listener = firebaseRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { subscriber.onNext(dataSnapshot); } @Override public void onCancelled(DatabaseError error) { FirebaseDatabaseErrorFactory.buildError(subscriber, error); }); subscriber.add(Subscriptions.create(new Action0() { @Override public void call() { firebaseRef.removeEventListener(listener); } })); } }); }
  22. RxFirebaseDatabase public Observable<DataSnapshot> observeValueEvent(final Query firebaseRef) { return Observable.create(new Observable.OnSubscribe<DataSnapshot>()

    { @Override public void call(final Subscriber<? super DataSnapshot> subscriber) { final ValueEventListener listener = firebaseRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { subscriber.onNext(dataSnapshot); } @Override public void onCancelled(DatabaseError error) { FirebaseDatabaseErrorFactory.buildError(subscriber, error); } }); subscriber.add(Subscriptions.create(new Action0() { @Override public void call() { firebaseRef.removeEventListener(listener); } })); } }); }
  23. RxFirebaseDatabase public Observable<DataSnapshot> observeValueEvent(final Query firebaseRef) { return Observable.create(new Observable.OnSubscribe<DataSnapshot>()

    { @Override public void call(final Subscriber<? super DataSnapshot> subscriber) { final ValueEventListener listener = firebaseRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(ataSnapshot dataSnapshot) { subscriber.onNext(dataSnapshot); } @Override public void onCancelled(FirebaseError error) { attachErrorHandler(subscriber, error); } }); subscriber.add(Subscriptions.create(new Action0() { @Override public void call() { firebaseRef.removeEventListener(listener); } })); } }); }
  24. Why Observable.create()? Observable.defer() : create a new Observable each time

    you get a subscriber Obserable.create() : can use same function for each subscriber. More efficient! Others Observable.fromCallable() : not really works with exceptions as it’s expected Observable.fromAsync() : quickly deprecated by RxJava (they were undecided) Observable.fromEmitter : seems final but still RxJava guys doing work (not tested yet by us)
  25. Old VS New Firebase v2.5.2 • No dependencies • No

    control over conflict resolution • UI browser super slow Firebase by Google v9.x • Google Play services • No control over conflict resolution • UI browser super fast BUT buggy • Remote config • Notifications • Dynamic links • Analytics • Crash reporting • Images upload
  26. Pros & Cons Pos • Autoscaling built-in • Robust APIs

    - Cross platform • Realtime • Declarative Security Rules model Cons • Storage format is in JSON, migration is hard to different system • No reporting tools to analyze Firebase queries • Need to build indexes manually • Data validation is hard • Costs