Getting Started With Cloud Firestore on Android – Firecasts
Articles Blog

Getting Started With Cloud Firestore on Android – Firecasts


TODD KERPELMAN: Hey
there, Android developers. Interested in getting
started with Cloud Firestore, the autosyncing,
scaling database in the cloud? Well, have I got
a video for you. It’s this one. So come on. Let’s save our data to the cloud
in this episode of “Firecasts.” [MUSIC PLAYS] So I’m working on
a little app here that lets me store an
inspirational quote. I mean, I can’t just be expected
to start doing work, right? I need an inspiring
quote, preferably from Einstein or maybe Marilyn
Monroe, to motivate me. And what better way to
do this than with an app? So my app here consists
of an edit text view where I can enter my
inspirational quote and then a second one here where I
can store the author’s name. I then have a Save
button where we’re going to save whatever inspiring
message our user has entered into the cloud. So later, we’ll load
whatever data our users save to the cloud and
display it with a big text view or something. So if you want to
follow along, go ahead and create your own
version of this app. Just make sure you have some
properties for the edit views and an onClick handler for the
button called, like saveQuote. Now, I’ve already gone ahead
and created a Firebase project in the Firebase console and
configured the Google services plug-in with my JSON file. If you don’t know what
I’m talking about, check out this Getting Started
video here and then come back. It’s OK. I’ll wait. Now, before we go ahead
and write some data, let’s take a moment to
understand how Cloud Firestore generally works. Frankly, this could be the
subject of its own separate video– and it probably
will be one day– but here is the
executive summary. Cloud Firestore is
a document database. That means it kind
of stores your data in a big tree-like
structure, kind of like the original
real-time database, but everything is placed into
documents and collections. You can think of a document as
something kind of like a map. It’s got key value pairs,
which the Firestore folks like to refer to as fields. And the values of these things
can be any number of things, from strings to numbers
to binary values to little smaller maps that are
kind of JSONy-looking objects. And collections are basically,
well, collections of documents. So there are a few rules
around the use of these things. The first is that
collections can only contain documents,
nothing else– no collections of strings or binary
blobs or anything else there. Second is that documents
can’t contain other documents, but they can point
to subcollections. So it’s very common to see
a collection containing a bunch of documents,
which then point to subcollections that contain
other documents, and so on. In a workout app,
for instance, I might have a Users collection. And this collection
would contain a document for each user. And then each of
those documents might point to a Workout subcollection
that, in turn, contains a document for each
different type of workout that this user has performed. And then maybe each one of these
has a History subcollection that keeps track of every
time the user performed one of these workouts, maybe
along with some average heart rate data or some
other stuff like that. Now, if you’re coming from
real-time database land, this kind of deep nesting
might be giving you heart palpitations. But don’t worry. This kind of data structure is
completely normal in the Cloud Firestore where
queries are shallow, meaning that when you
grab data from a document you’ll grab just that document
not any of the documents contained in any of the
subcollections below, which is nice. The third rule is that
the root of your database can only consist of collections. Now, in a normal
production app, this is going to feel pretty natural. You’re going to have
your collection of items and your collection of users
and your collection of games or what have you. The one time it’s going
to seem kind of weird, it’s when you’re creating
a little test app like ours and you just want to
save like two strings. So looking at our
app, at the top level, I’m going to start
with a collection that I’m calling sampleData. This will then contain
one single document called inspiration. This document will
itself have two key value pairs, or fields, one called
quote and another called author. Incidentally, note that this
is basically a global variable that I’m altering–
meaning that I’m not storing one quote per user, I’m
letting everybody in the world alter this one document. If I were looking to save a
different quote per user, which I might do in an actual
app, I’d probably be setting up a Users
collection and creating a different document
for each user. Make sense? All right. Let’s start building. So first things first,
I need to make sure I have Firestore installed, and
so I’ll go into my app’s Gradle file and add this line here to
add Firestore to my project. Obviously, this
version number will be different than what’s current. Heck, I’m not even sure
this version will work by the time you see this video. So do make sure that you
grab the most recent version from our documentation. And then I’ll tell Android
Studio to go ahead and sync, and we’re good. So next, in my main
activity here, I’m going to head on down
to my saveQuote call. So in there, I will
first grab the text from my two edit text views. So we’ll get the
views, and then we will grab the strings from them. And then maybe I’ll do a check
to make sure they’re not empty. Next, I’ll create the data I
want to save in my document. Now, this will be a map
of type String, Object that I will implement
as a hash map. So I’ll use the
key quote and then the string of my quote
text view as my value. And then I’m going to do the
same thing for the author. And let’s do the right thing and
Command+Option+C these things so we can make these
key names constants. OK, that’s better. Now, I just need to
save this to the cloud. And to do that, I need to
specify in which document I want to put this data. So we do that through an object
known as a document reference. It turns out I’ll be using the
same reference multiple times throughout this project,
so I’m going to make it a field up here in my class. And let’s initialize
it up here, too. Now, there are a few ways of
setting my document reference. First, I could call
FirebaseFirestor e.getInstance.collection
sampleData.document Inspiration. Now, I kind of like doing
this because it serves as a nice reminder that you’re
always going to alternate between collections
of documents, but it does start to
look a little nutty when you get several layers deep. This is kind of silly. So an alternative that I
prefer is calling document where I pass along a
slash-separated string as our path. So in our case, the path would
be sampleData/inspiration. And just remember
that in your path, you’re always going
to be alternating between collections, documents,
collection, document, and so on. So now that I’ve
specified my document, let’s go back to my
saveQuote method, where I’m going to call set
on the document reference. And that’ll take in the data I
created above as the contents of my document. Now, this call will replace my
current document if it exists and create it if it doesn’t. It also conveniently creates
the sampleData collection 2, so I don’t need to worry
about that not existing. Now I’m going to chain
on an OnSuccessListener, like so, where we can
print a debug message. And let’s Command+Option+C
this puppy, too. And then we can add on and
OnFailureListener where we can print out any error messages. And that’s it. All right. For those of you who are
all about fewer listeners in your call, you
could also handle this with a single
OnCompleteListener, like so, 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. All right. Let’s give this a try. So I’m going to start
up my app, and I’m going to enter this very
inspirational quote here in the text field. And I’m pretty sure
that was said by Plato. I’ll hit Save and– oh, whoops, looks like we’re
getting an authorization error. And this is because, just
like the real-time database, my Cloud Firestore
implementation contains a set of security rules
that determine whether or not a certain action
will be permitted. And by default, they’re
set up so that nobody can read or write to the database. So the correct solution
here would probably be to add in some sign-in
using FirebaseAuth and then create some proper,
well-thought-out security rules based on what information
I’m willing to share to each particular user. That said, all of that would
make this a much longer video than it already is, so I’m just
going to do a bit of a hack here and make my sampleData
documents open to the public. So let’s head on over
the Firebase Console. I’ll select my project, go
here to the Database section, 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 allow reading and writing to anything
that’s part of my sampleData collection. Now, this is a pretty
terrible idea from a security perspective, but at least
I’ve contained the damage to just what’s in my
sampleData collection. So I’ll publish that,
and we are done. OK. Let’s give it another try. I’m going to wait a few seconds
and then go back into my app. Hit Save. And, huh, looks like it worked. And I can verify this by going
back to the Firebase console. We’ll select the
Data tab, and then I can look at our
sampleData collection, find our Inspiration document. And sure enough, it looks like
we’ve saved our inspiring quote to the world. Woo hoo. OK. Next step, we need to show our
users this inspirational quote by grabbing that
data from the cloud and populating some kind
of text 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. But I know that, for
some of you out there, the idea of creating a real-time
listener for all your data is weird and strange,
and sometimes you just want a basic fetch
call to get your data. So I’m going to show you
how to do that first, and then we can talk
about getting fancy with some real-time listeners. So let’s create a Fetch button. I’m going to add some
constraints and some text for the button. It’s just a button,
nothing too fancy here. And then I’m going
to stick a text view in the middle of
my screen so that I have a user-visible location
where I can display the quote. We’ll fix that up. I’ll add in some default
text, give it a name. All right. Next up, I’ll add a placeholder
method called fetchQuote, and I’ll make that my
button’s onClick handler. All right. Let’s edit this method. So I already have my
document reference. As you recall, I created
it as a field earlier. So I can simply call
get on that reference to fetch the document. Now, for this call, I can also
add an onSuccess listener. And you’ll notice that
this time the listener takes in a document snapshot. A document snapshot
is basically an object that represents your document. You can find out its ID,
read some metadata about it, make sure the underlying
document it represents really exists, and most importantly
grab the data that it contains. We’ll see if our
document exists. And if it does, I’m going
to get our quote by grabbing DocumentSnapshot.getString. And I’ll use that QUOTE_KEY
constant I created earlier. I’ll do the same thing
for my author name. And incidentally,
there are other ways of getting at this data. If I wanted to fetch it all
at once, I could call getData, and then that would give me
my entire document in a string object map. And for more
sophisticated projects, document snapshots
in Cloud Firestore have this nifty
toObject helper function that will look probably
familiar if you’ve ever used the real-time database before. Basically, this
will take the data that you get back
from the database and attempt to create an object
of the type that you specify. It’ll take whatever values
it gets back from Firestore and try to set those as fields. So for this to work,
you have to make sure that the target object
has a constructor that accepts no arguments, and
it’s probably a good idea to have getters for
these fields, too. So if I wanted to make
inspiring quote its own class, it might look a little
something like this. And yes, apparently it’s
fine for those field names to be private like that. And while this custom objects
stuff is pretty neat, for now, I think I’m just going to
stick with my original two getString calls. Next, we’ll want to
display the text on screen. So let’s make sure
we have a field that references our quote text view. We can set it in onCreate, and
then we’ll set the text value. And we’re done. And yeah, I should probably
add an onFailure listener here, too. But for brevity’s
sake, let’s skip that. So let’s run this. We’ll click Fetch. And there we go. I can save my inspirational
quote to the cloud, and now we can load it
with a click of a button. So this is great. We’ve got our data
successfully saved and loaded from Cloud Firestore. But what if you are
interested in getting your data in real time? What if this explicit
fetching seems quaint and old fashioned to you? Well, let’s show you how to get
your data in real time, too. Basically, the process is
going to work nearly the same. Let’s override my
onStart method. And in there, I’m going
to bring up my DocRef. But now, instead
of calling get, I’m going to call
addSnapshotListener. And I’ll create a
new event listener for the document snapshot. Now, this will fetch my document
the first time I set it up, but then it will also
grab updated data any time thereafter when
that document changes. So my onEvent function gets
passed in a document snapshot just like my onSuccess
handler below. So in fact, I’m just going
to copy the exact same code from my fetch call into here
to update the text view. And maybe I’ll
print out a warning if I do get an
exception like this. Now, while this will work, we
also want to do the right thing and turn off this listener when
it isn’t needed, for instance when my activity is off screen. This will help to keep
your network usage low, which means better
battery life for your user and potentially lower database
costs for you, both of which are good things. Now, I could track this
listener manually and then remove it at an appropriate
point like in my onStop method, but there’s an easier way. You see, there’s an alternate
call for addSnapshotListener where you can pass in an
activity as the first argument, and this activity is
telling our event listener, hey, when this
activity stops, you can go ahead and
detach this listener. And so by specifying this
as my first argument, my listener will automatically
do the right thing and detach when my
main activity stops. So let me run the app again. You can see that, thanks
to my Snapshot Listener, my label automatically
gets updated with the inspirational Plato
quote that was used previously. And then, if I change
my inspirational quote to this one– I think Einstein said this– you can see that my text view
gets updated automatically without my having to even
touch that Fetch button. Wow. Gee, that was fast. Maybe too fast, right? It looked like my
text new got updated before I even got the console
message that my data was saved to the cloud. How did that happen? Well, what’s going on
is that Cloud Firestore is making my app run as speedy
as possible by notifying me of changes that happen
locally as if they had happened on the server. But in the meantime,
it’s still going ahead and updating that data
remotely in the background. Now, it turns out
my client does still receive an update from
Firestore that this data has been changed on that server. But by default, the
Firestore library will ignore this event because,
basically with the exception of a little bit of metadata
that says yes, this is really from the server,
it’s identical to the first. [STRUMMING] Now, if you wanted, you
could get notified by the SDK about this second
event, the one that actually happened when the
write happens on the server. You do this by creating some
options for your Document Listener that say, yes,
notify me even when just the metadata changes. You would pass those options
in, add in a little debugging to print out what we get, and
let’s add in one more quote. Notice that when I
save this thing now, my callback is
getting called twice– once for the change
in my local cache and then once on the server. Now, there may be times when
this behavior is what you want, but honestly, most of the time
the default behavior works just fine. So I’m going to go back
to what we had before, and you probably should, too. So there you go. Congratulations. You are now saving
your data in one of the most powerful and
sophisticated online databases in the world and using it to
store two lines of text, which maybe is a little overkill. But in a real app, you’ll
appreciate this power. Trust me. Now, there’s a lot more to
learn about Cloud Firestore, including more details on
how that data is structured, how subcollections
work, and how to run some more sophisticated
queries, all of which are great topics
for future videos. In the meantime, go back
to those security rules and change them to
be a lot more secure. And when you’re
done with that, be sure to check out
the documentation and try using Cloud
Firestore in your own app. As the saying goes, the
journey of 1,000 miles begins with reading
the documentation. I think Ruth Bader
Ginsburg said that. [MUSIC PLAYING]

75 thoughts on “Getting Started With Cloud Firestore on Android – Firecasts

  1. How can we add multiple quotes in inspirational document ?in the video when you try to add quote previous one gets updated

  2. This is amazing, I'm gonna add up to the wish of getting a video about queries, specially about multiple arguments queries

  3. When should we use it? From what i understood, there is nothing you can store in firestore but not in the realtime database, plus there are some constraints in the firestore. So when it is preferable to use firestore?

  4. Hey, I want to know what is the best to test Firestore apps without mocking out a bunch of calls. I'd like you to provide some in-memory store mechanism or something to test with.

  5. Wow, what a good timing. I was just about to implement Firebase Realtime Database into my new app, but now I'm feeling like I need to do a little research about this new service

  6. Can you please clarify me that what is the difference between Realtime Database and Cloud Firestore. I love this feature because it is very cheap as compared to Real-time Database. One more question, Is there is any limitation on simultaneous user in Cloud Firestone.

  7. Im trying to insert custom object in firestore using the add() method instead of set() method as shown in video but my app crashes my question is can we insert custom objects using add() method or have to use set () method for inserting custom objects?

  8. Nice step up from the RTD, especially like the fact that we can now make powerful queries and use both sets of databases in our app! No need to restructure existing code !

  9. https://www.youtube.com/redirect?redir_token=W6ciwqqx4CIE3bnxo-0C4UHsU1p8MTUwNzMyNjM5NkAxNTA3MjM5OTk2&event=video_description&v=kDZYIhNkQoM&q=https%3A%2F%2Fgoo.gl%2FKamG3V

  10. It would be great if someone can give answers for:
    1. How to convert from realtime-database to this?
    2. Are there any sample for firebase cloud function?

  11. Give me only a tip about my old database realtime structure. Whats I do? I not see how import db.json in firestore console. There is some way for this? Or I will need create a 'robot' for to read my old database and insert in new structure in firestore? Thanks everyone

  12. Hello, I'm leaving this comment BEFORE i watch this video. I would like to take the time and say thank you for putting this out. Your doing god's work.

  13. Great Video – Thank you! Just one question…. if I have multiple users accessing a document – and they need to take an item from that document and then remove it so another user cannot use that item – how does that work? What if both users get the document at the same time – and both take the top item… Can I put a hold on the read/write status of the doc until that user is finished with it or is this done automatically?

  14. I want to make structure like Book-Chapter-all records….But its not created..It add one more subcollection …how to make this Book-Chapter-all records

  15. Hello…
    My laptop not able to load Fire Base Console. it just getting loading, loading and still loading.
    If i go through my brothers laptop it just load in seconds in same Network and same email.
    so what can I do?
    Humble request to reply me fast with effective solution . ….

  16. awesome.. how to write query for sub collection in android and how to store data in these sub collection??

  17. Hey Firestore team, I would be honered if you would take a look at my Firestore serie and leave a comment there: https://www.youtube.com/watch?v=vMnCU6KKHd4

  18. 12:08 I think this way the app would crash if the user doesnt have the permission to access the database. Because then the documentSnapshot is null and calling .exists() will throw an exception. Instead I would check if e != null beforehand and then return to leave the method before trying to call .exists()

  19. can i do above same for two apps like if i write it in app A
    and display in app B by fetching from Firestore server

  20. Just came from attempting to use google play games services. This is like the light to the endless pit of black "explained but really not".

  21. Getting started with Firebase on Android video: https://goo.gl/KamG3V

    Official Cloud Firestore Android documentation: https://goo.gl/tTJ2yK

    Add the Firecasts playlist! https://goo.gl/n2XqG1

    Subscribe to the Firebase Channel: https://goo.gl/9giPHG

Leave a Reply

Your email address will not be published. Required fields are marked *

Back To Top