Rxjava 2.0 wrapper on Google's Android Firebase library.
This repository started as a personal usage of Nick Moskalenko RxFirebase library. You can check his work here.
dependencies {
compile 'com.github.frangsierra:rx2firebase:1.1.3'
}
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
One of the differences between RxJava and RxJava 2 is that RxJava 2 no longer accepts null
values. Throwing a NullPointerException
immediately. For this reason some of the methods of the library as been redesigned to return a Completable
instead of a Observable<Void>
. For example:
@NonNull
public static Observable<Void> updateEmail(@NonNull final FirebaseUser firebaseUser, @NonNull final String email) {
return Observable.create(new Observable.OnSubscribe<Void>() {
@Override
public void call(final Subscriber<? super Void> subscriber) {
RxHandler.assignOnTask(subscriber, firebaseUser.updateEmail(email));
}
});
}
@NonNull
public static Completable updateEmail(@NonNull final FirebaseUser firebaseUser, @NonNull final String email) {
return Completable.create(new CompletableOnSubscribe() {
@Override
public void subscribe(CompletableEmitter emitter) throws Exception {
RxCompletableHandler.assignOnTask(emitter, firebaseUser.updateEmail(email));
}
});
}
RxCompletableHandler
manages the CompletableEmitters in the same way that RxHandler
manages the Subscriber
.
You can check all the differences between RxJava and RxJava 2.0 in the next Link
Library provides set of static methods of classes:
- RxFirebaseAuth
- RxFirebaseUser
- RxFirebaseDatabase
- RxFirebaseStorage
It also provides a custom implementation of FirebaseRecyclerAdapter
:
- RxFirebaseRecyclerAdapter
Sign in with email and password:
RxFirebaseAuth.signInWithEmailAndPassword(auth, email, password)
.map(authResult -> authResult.getUser() != null)
.take(1)
.subscribe(logged -> {
Log.i("Rxfirebase2", "User logged " + logged);
});
You can observe values providing the Class of expected data like:
RxFirebaseDatabase.observeSingleValueEvent(getPostsRef().child("posts"), Post.class)
.subscribe(post -> {
//Do something with yourpost
});
or providing your own mapper between DataSnapshot and your data type:
RxFirebaseDatabase.observeSingleValueEvent(getPostsRef().child("posts"),
dataSnapshot -> {
// do your own mapping here
return new Author();
})
.subscribe(author -> {
// process author value
});
There are some pre-defined mappers to make things easier:
RxFirebaseDatabase.observeSingleValueEvent(getPostsRef().child("posts"), DataSnapshotMapper.listOf(PostComment.class))
.subscribe(blogPost -> {
// process postcomment list item
});
RxFirebaseDatabase.observeSingleValueEvent(getPostsRef().child("posts"), DataSnapshotMapper.mapOf(PostComment.class))
.subscribe(PostCommentAsMapItem -> {
// process blogPost as key-value pair
});
Download file from Firebase storage
RxFirebaseStorage.getFile(getStorageRef(), targetFile)
.subscribe(taskSnapshot -> {
Log.i("RxFirebaseSample", "transferred: " + snapshot.getBytesTransferred() + " bytes");
}, throwable -> {
Log.e("RxFirebaseSample", throwable.toString());
});
or download file as bytes array
RxFirebaseStorage.getBytes(getStorageRef(), 1024 * 100)
.subscribe(bytes -> {
Log.i("RxFirebaseSample", "downloaded: " + new String(bytes));
}, throwable -> {
Log.e("RxFirebaseSample", throwable.toString());
});
RxFirebaseQuery is a builder class used to work together with methods from RxFirebaseDatabase that allow you to retrieve data from multiple databaseReferences. Doing this allow you to build and create dynamic queries to retrieve database objects from references retrieved from different tables easily.
At the moment RxFirebaseQuery just allow the user to create the queries and retrieve the data. Filters should be done with the DatabaseReference
items that you pass to the constructor. In other hand for update and delete data you should use Firebase
method updateChildren()
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
DatabaseReference from = reference.child("tweets");
Query where = reference.child("users").child(userId).child("feedReferences");
RxFirebaseQuery.getInstance()
.filterByRefs(from, where)
.asList()
.subscribe(dataSnapshots -> {
Log.i("RxFirebase", "Retrieved a total of " + dataSnapshots.size() + " tweets");
for (DataSnapshot dataSnapshot : dataSnapshots) {
Tweet tweet = dataSnapshot.getValue(Tweet.class);
Log.i("RxFirebase", "New tweet for user feed: " + tweet.getDescription());
}
});
RxFirebaseRecyclerAdapter was created looking for a way to manage the RxFirebaseChildEvent<DataSnapshot>
items recieved with the observeChildEvent
method. It is an abstract class based on FirebaseRecyclerAdapter but modifying the query and firebase call dependency.
Doing this, now it only recieve a RxFirebaseRecyclerAdapter and using the method manageChildItem
it will manage the ChildEvent
doing the right task based on the EventType
of the item:
For example:
RxFirebaseDatabase.observeChildEvent(getPostsRefFromGroup(groupId))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(post -> {
getView().managePost(post);
getView().showLoadingProgressBar(false);
}, throwable -> {
getView().showLoadingProgressBar(false);
getView().showReloadLayout(true);
}));
public void managePost(RxFirebaseChildEvent<DataSnapshot> post) {
if(postRecyclerView.getVisibility() != View.VISIBLE) {
postRecyclerView.setVisibility(View.VISIBLE);
}
if (adapter == null){
adapter = new PostAdapter(this, this);
postRecyclerView.setAdapter(adapter);
}
adapter.manageChildItem(post);
}
public class PostAdapter extends RxFirebaseRecyclerAdapter<PostViewHolder, Post> {
private static final String TAG = "PostAdapter";
public PostAdapter() {
super(Post.class);
}
@Override
public PostViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//Initialize your Holder
}
@Override
public void onBindViewHolder(PostViewHolder holder, int position) {
Post post = getItems().get(position);
//bind your post
}
@Override
protected void itemAdded(Post item, String key, int position) {
//Add the refs if you need them later
item.setRef(key);
Log.d(TAG, "Added a new item to the adapter.");
}
@Override
protected void itemChanged(Post oldItem, Post newItem, String key, int position) {
//Add the refs if you need them later
newItem.setRef(key);
Log.d(TAG, "Changed an item.");
}
@Override
protected void itemRemoved(Post item, String key, int position) {
Log.d(TAG, "Removed an item.");
}
@Override
protected void itemMoved(Post item, String key, int oldPosition, int newPosition) {
Log.d(TAG, "Moved an item.");
}
}