You can store your data in the cloud using Cloud Firestore. You can sync it across all your devices or share them with multiple users. It comes with robust client libraries, full support for offline mode. Your app will continue to work just fine whether you’re connected or not. A comprehensive set of security rules to help you manage access and an easy-to-use data browsing tool. It also lets you structure your data in ways that make sense to you thanks to its powerful querying and fetching capabilities.
Cloud Firestore works in real time, automatically fetching changes from your database as they happen, or you can request and fetch data manually.It’s completely up to you.
Getting Started with Cloud Firestore on Android
So I’m working a little app here that lets me store a thought. My App consists of an EditText where I can enter my thought and then the second one here where I can enter the publisher’s name and then I have Publish button where we’re gonna save whatever thought our user has entered into the cloud so later we’ll load whatever data our users saved to the cloud and display it with a big Listview or something
Enable Firestore in Firebase
In order access to Firestore you need to enable Firestore in Firebase Console.
Add Firebase to your Android project
Create a Firebase project in the firebase console and configure the Google services plug-in with JSON file.
Firestore is a Document Database
Firestore store your data in a big tree like structure kind of like the original real-time database but everything is placed into documents and collections. For more about a document database, read this post. Add Firestore Dependency to your app
Let’s start building so first thing you need to make sure you have Firestore installed. Into app.gradle file add Firestore.
dependencies { .... compile 'com.google.firebase:firebase-firestore:16.0.0' }
In main activity here I’m gonna head on down to my publishThought
call.
public void publishThought(View view) { final String name = nameView.getText().toString().trim(); String thought = thoughtView.getText().toString().trim(); ..... }
Cloud Firestore also supports writing your own Java objects with custom classes. Cloud Firestore will internally convert the objects to supported data types.Each custom class must have a public constructor that takes no arguments. In addition, the class must include a public getter for each property. Now you just need to save this to the cloud and to do that you need to specify in which document you want to put this data so you do that through an object known as a DocumentReference
let’s initialized it up.
DocumentReference docRef; .... docRef = FirebaseFirestore.getInstance().document("thought/lifeThought");
I pass along a slash-separated string as our path so in our case, the path would be “thought/lifeThought“ Just remember that in your path you’re always going to be alternating between collections documents collection document and so on. Now that I’ve specified my document. In my
publishThought()
method where I’m going to call set on the document reference and that will take in the data. I created above as the contents of my document this call will replace my current document if it exists and created if it doesn’t it also conveniently create the sample data collection too so I don’t need to worry about that not existing now I’m going to chain on an addOnSuccessListener
like so where we can print a debug message. And then we can add an addOnFailureListener
listener where we can print out any error messages.
public void publishThought(View view) { .... if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(thought)) { Thought th = new Thought(thought, name); docRef.collection(PUBLIC_THOUGHT).add(th) .addOnSuccessListener(new OnSuccessListener<DocumentReference>() { @Override public void onSuccess(DocumentReference documentReference) { Log.d(TAG, "DocumentSnapshot written with ID: " + documentReference.getId()); nameView.setText(""); thoughtView.setText(""); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.w(TAG, "Error adding document", e); } }); }
For those of you who are all about fewer listener in your call, you could also handle this with a single OnCompleteListener
like and then just check in here to see if your task is successful either way works and honestly it’s just really up to you which method you prefer.
Error on Document Writing com.google.firebase.firestore.FirebaseFirestoreException: PERMISSION_DENIED: Missing or insufficient permissions.
Just like the real-time database cloud, Firestore implementation contains a set of security rules that determine whether or not a certain action will be permitted.By default they’re set up that nobody can read or write to the database.I’m willing to share with each particular user.So I’m just going to do a bit a hack here and make my sample data documents open to the public. I’ll select my project go to database selection and then make sure I select cloud Firestore for my list of database options then I will click the rules tab and then I’m going to add these lines here to allows reading and writing to anything that’s part of my sample data collection now this a pretty terrible idea from a security perspective but at least I’ve contained the damage to just what’s in my sample data collection so I’ll publish that and we are done. So I’m going to start up my app, and I am going to enter thought in the text field and I hit publish button.
I can verify this by going back to the Firebase console we’ll select the data tab and then I can look at our data collection find our document and sure enough look likes we’ve saved our inspiring thought to the world.
Get Data with Cloud Firestore
We need to show our users this inspirational thought by grabbing that data from the cloud and populating in some kind of list view with it now like the real-time database cloud Firestore lets me listen to changes in the database and update my app in real time. So let’s create a Thought List I ’m gonna add a Recyclerview in the middle of my screen that has a TextView where I can display the thought and publisher name. I already have my document reference.
Perform Simple Query in Cloud Firestore
Cloud Firestore provides powerful query functionality for specifying which documents you want to retrieve from a collection. These queries can also be used with either get()
or addSnapshotListener().
private Query query; .... query = docRef.collection(PUBLIC_THOUGHT).orderBy("timestamp", Query.Direction.DESCENDING) .limit(LIMIT);
Get Realtime Updates with Cloud Firestore
You can listen to a document with the onSnapshot()
method. An initial call using the callback you provide creates a document snapshot immediately with the current contents of the single document. Then, each time the contents change, another call updates the document snapshot.
public void startListening() { if (mQuery != null && mRegistration == null) { mRegistration = mQuery.addSnapshotListener(this); } } @Override public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) { if (e != null) { Log.w(TAG, "onEvent:error", e); onError(e); return; } // Dispatch the event Log.d(TAG, "onEvent:numChanges:" + documentSnapshots.getDocumentChanges().size()); for (DocumentChange change : documentSnapshots.getDocumentChanges()) { switch (change.getType()) { case ADDED: onDocumentAdded(change); break; case MODIFIED: onDocumentModified(change); break; case REMOVED: onDocumentRemoved(change); break; } } }
When I publish thought now my callback is getting called twice once for the change in my local cache and then once on the server.This is because of an important feature called latency compensation.