ezhome - files.meetup.comfiles.meetup.com/20372995/Firebase_and_RxJava - 1st Athens Andro… ·...

Post on 23-Aug-2020

0 views 0 download

Transcript of ezhome - files.meetup.comfiles.meetup.com/20372995/Firebase_and_RxJava - 1st Athens Andro… ·...

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.

@ezhomeinc

Gardener App Capabilities

Real-time database

Coordinators & Monitoring team

More...

Easy & Secure authentication

More...

Offline gardener actions

Offline photos uploading

Share state

More...

Real-time Feature Toggle

Firebase Database

• Cloud-hosted NoSQL database• Real-time - Non HTTP• Data stored as JSON• Offline • Accessible by different devices• Security rules• Multiple Authentication Providers

Firebase Authentication

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": { } }}

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": { } }}

Avoid nesting data

When you fetch data at a location in firebase, you also retrieve all of its child nodes.

ExampleI want show the conversation titles from chats:

databaseReference.child("chats");

More... Fatal Exception: java.lang.RuntimeException: Uncaught exception in Firebase runloop. Please report to support@firebase.com

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)

Caused by java.lang.OutOfMemoryError: [memory exhausted] at dalvik.system.NativeStart.main(NativeStart.java)

More...

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": { } }}

More...{ "messages": { "one": { "m1": { "name": "eclarke", "message": "The relay seems to be malfunctioning.", "timestamp": 1459361875337 }, "m2": { ... }, "m3": { ... } }, "two": { ... }, "three": { ... } }}

Nested VS Flatten

Flatten Nested Flatten

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);

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);

Gardener App Architecture + RxJava

Inspired by@fernando_cejas of

SoundCloud

RxFirebase by ezhome

RxJava wrapper on top of Firebase. The library includes:• RxFirebaseAuth• RxFirebaseDatabase

https://github.com/ezhome/Android-RxFirebase

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();

//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

//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

//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

//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

//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

//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

//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

//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

RxFirebaseDatabasepublic 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); } })); } });}

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); } })); } });}

RxFirebaseDatabasepublic 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); } })); } });}

Why Observable.create()?

Observable.defer() : create a new Observable each time you get a subscriberObserable.create() : can use same function for each subscriber. More efficient!

OthersObservable.fromCallable() : not really works with exceptions as it’s expectedObservable.fromAsync() : quickly deprecated by RxJava (they were undecided)Observable.fromEmitter : seems final but still RxJava guys doing work (not tested yet by us)

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

Pos & 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

Is it production ready?

Questions

We are hiring!!!ezhome.com/careers

github.com/ezhomegithub.com/spirosoik

@spirosoik