Firebase Database in Flutter – WeightTracker 3

Firebase Database in Flutter – WeightTracker 3

In this post I’m going to go through adding Firebase Database to a Flutter application. The presented development is part of my Weight Tracker app (simple app for tracking weight), so the development will be based on that and focused on that purpose.

Let’s get to it!

 1. Setting up Firebase

First thing we need to do is set up Firebase integration. It is clearly explained in Firebase’s Codelab, so before moving on I would recommend you going through point 5 in order to connect to Firebase.

For this course we are not going to use Authentication, however the default rules for Firebase Database require users to be authenticated. To change that we will modify database’s rules file to allow anyone to read and write to the database:

{
  "rules": {
    ".read": true,
    ".write": true
  }
}

After we set everything up, all we need is to add firebase dependency to our flutter project’s pubspec.yaml file

dependencies:
  flutter:
    sdk: flutter
  firebase_database: 0.0.12

and we are ready to go!

2. Pushing data to database

Firebase database plugin is very simple to use. To get main reference of our application all we need to do is get access to static field in FirebaseDatabase class.

final mainReference = FirebaseDatabase.instance.reference();

If we would like to get into more specific child of our database, we can simply call mainReference.child(“name_of_child”).

To push an object into database we can just call push and set methods on reference object.

mainReference.push().set(...);

However the set method doesn’t accept just an object. It needs to be a dynamic value already in a json-map format. In order to transform our object to the format we want, I added toJson method:

class WeightEntry {
  DateTime dateTime;
  double weight;
  String note;

  WeightEntry(this.dateTime, this.weight, this.note);

  toJson() {
    return {
      "weight": weight,
      "date": dateTime.millisecondsSinceEpoch,
      "note": note
    };
  }
}

Now we can call

mainReference.push().set(entry.toJson())

And we end up with an entry stored in our database.

{
 "-KsUdXjd1VSn7iB1s9xo" : {
   "date" : 1503769535565,
   "weight" : 60
 }
}

3. Reading data from database

In order to get data from database, we add listener to the reference we are interested in (in that case it will be mainReference). Once we get the value, we will simply add it to state’s list and call setState method.

Side note: I present only getting value from database and adding it to local list. If you are interested in how to display it, check out my GitHub repository for full code. Link provided at the end of post.

class _HomePageState extends State<HomePage> {
  List<WeightEntry> weightSaves = new List();

  _HomePageState() {
    mainReference.onChildAdded.listen(_onEntryAdded);
  }
  _onEntryAdded(Event event) {
    setState(() {
      weightSaves.add(new WeightEntry.fromSnapshot(event.snapshot));
    });
  }

  ...
}
import 'package:firebase_database/firebase_database.dart';

class WeightEntry {
  String key;
  DateTime dateTime;
  double weight;
  String note;

  WeightEntry(this.dateTime, this.weight, this.note);

  WeightEntry.fromSnapshot(DataSnapshot snapshot)
      : key = snapshot.key,
        dateTime =
            new DateTime.fromMillisecondsSinceEpoch(snapshot.value["date"]),
        weight = snapshot.value["weight"].toDouble(),
        note = snapshot.value["note"];

  toJson() {
    return {
      "weight": weight,
      "date": dateTime.millisecondsSinceEpoch,
      "note": note
    };
  }
}

As you can see, database listener consumes Event object. The actual object we are interested in is in event.snapshot.value. However it is same dynamic format we have pushed. In order to parse it to WeightEntry, I added constructor accepting DataSnapshot and then getting specific fields from value. I also added Key to the class, which is the unique value Firebase is creating on push. It will be needed in editing.

4. Updating data

Since we added Key to the WeightEntry model, it is very easy to update a value in database.

Code below shows how to edit value in database once we have the object we want to pass:

_pushEdit(WeightEntry weightEntry) {
  mainReference.child(weightEntry.key).set(newEntry.toJson());
}

Calling child(key) will return a reference to object we want to edit, then setting new value will make a deal. This action will result in updated entry in database, however our application won’t notice it. In order to stay updated with data edits, we need to add change listener.

class _HomePageState extends State<HomePage> {
 List<WeightEntry> weightSaves = new List();

  _HomePageState() {
    mainReference.onChildAdded.listen(_onEntryAdded);
    mainReference.onChildChanged.listen(_onEntryEdited);
  }
  _onEntryEdited(Event event) {
    var oldValue = weightSaves.singleWhere((entry) => entry.key == event.snapshot.key);
    setState(() {
      weightSaves[weightSaves.indexOf(oldValue)] = new WeightEntry.fromSnapshot(event.snapshot);
    });
  }
  ...
}

Now on every child changed in mainReference, we update this child in our local listView and call setState.

BONUS: If you want your application to store data in local memory in case of no network connection, this is the way 🙂

FirebaseDatabase.instance.setPersistenceEnabled(true);

5. End notes

Wiring up Flutter application with Firebase is very easy and straight forward. I strongly encourage everyone to try it out. In the near future I will go through Firebase Authentication for more complex usage of Firebase (link will be provided). If you are interested in more Flutter-Firebase content, you can see the Codelab I talked about earlier. You can also check out firebase_database plugin itself.

I hope you liked that post, I would be grateful for any feedback so please feel free to leave a comment 🙂

That’s it folks!

You can find whole project here. (You need to create own google-services.json to connect to Firebase)

16 thoughts on “Firebase Database in Flutter – WeightTracker 3

      1. What I mean is… with Step 3. you are reading data from Firebase Realtime database right? can you also include an example in which, after you have read the data from the database, you will use the data to pre-populate the form fields (like weight text field, etc..)

  1. Cool post!

    I have problems with the WEIGHTTRACKER, flutter not found import ‘package:intl/intl.dart’;
    What can i do?

    Sorry for my english

    1. Hi!
      Error is probably caused by Flutter updates made since publication of this post. If you use most recent version of app (https://github.com/MSzalek-Mobile/weight_tracker) it should work well.
      If you want to use version linked in the post try adding missing import in pubspec.yaml. I think that in that case dates may not display correctly (because of changes in Flutter).
      Let me know how it goes 🙂

      1. Thank you for the reply, i could make it works. It was the missing depency in the pubspec. Im going to try the last version too.
        Thanks!

  2. Hi man! Great use case.

    Say me how to get / setting / generate key.properties file? I’m newbie on Firebase.

    Can you help me?

    Error:
    FAILURE: Build failed with an exception.

    * Where:
    Build file ‘C:\Projetos\weight_tracker\android\app\build.gradle’ line: 21

    * What went wrong:
    A problem occurred evaluating project ‘:app’.
    > C:\Projetos\weight_tracker\android\key.properties (O sistema não pode encontrar o arquivo especificado)

  3. Great one – I cant find a lot (useful stuff) about flutter with firebase on youtube so I started searching the web. Now I finally found something that actually works!

  4. How to handle relational data like
    {
    “weight”: weight,
    “date”: dateTime.millisecondsSinceEpoch,
    “invoice line”: {
    “name”: “Product 1”,
    “price_unit”: 111
    {
    “name”: “Product 2”,
    “price_unit”: 222 }
    }
    }

    1. Hey,
      this highly depends on nature of your app.
      One solution would be to ditch listening for updates for just one time requests where you could download all neede data in one async function. You could also download list of all products and have them as a dictionary in memory (it would obviously depend on size of the list). Other way would be to add database listener for every product you need in invoice line. I hope it helps somehow… Please tell me how you handled it 😉

Leave a Reply

Your email address will not be published.