You are on page 1of 23

Flutter - Firebase Realtime Database CRUD

Firebase Realtime Database

- A cloud-hosted database that helps us to store and sync data with NoSQL
database in realtime to every connected client platforms like Android, iOS,
and Web.
- Firebase store all the data in JSON format and any changes in data reflects
immediately by performing a sync operation across all the platforms.
- Allows us to build a flexible realtime app easily with minimal efforts.

Firebase Realtime Database feature


- Realtime: – It means the data is synchronized with all connected devices
within milliseconds of changes being made to the data.
- Offline: - The Firebase Realtime Database persists data on your device. The
data is always available, even app offline. The data is automatically synced
once the app comes back online.
- Security: – You can define your security rules which controls who has what
access to your Firebase database. You can also integrate Firebase
Authentication to control access to your data.

How data store on Firebase cloud?


{
"counter" : 2,
"user" : {
"-LyUGMcrDrlTBOeumtgJ" : {
"email" : "elte.dev@gmail.com",
"hp" : "083833838884",
"nama" : "ilham",
"usia" : "29"
},
"-LyUJbPOGxThn7YrPvva" : {
"email" : "faizuddin95@gmail.com",
"hp" : "081234738292",
"nama" : "faiz",
"usia" : "25"
}
}
}

How can enable offline persistence in Flutter?


Firebase provides great support when your application in offline mode. It
automatically stores the data offline when there is no internet connection. When the
device connects to the internet, all the data will be pushed to the realtime database
FirebaseDatabase database = new FirebaseDatabase();
database.setPersistenceEnabled(true);
database.setPersistenceCacheSizeBytes(10000000);
Contoh implementasi
1. Buat project baru Flutter.

2. Pilih Flutter Application.


3. Sesuaikan konfigurasinya

4. Konfigurasi nama package


5. Masuk ke https://console.firebase.google.com/u/0/
6. Add project.
7. Buat nama project-nya, UMC-NamaAnda, misal : UMC-elte

8. Centang Google Analytics


9. Pilih Default Account

10. Buat database baru.

11. Pilih production mode


12. Pilih nam5(US).

13. Pilih realtime database


14. Pilih import json

15. Simpan json berikut dengan nama test-firebase data.json.


{
"counter" : 2,
"user" : {
"-LyUGMcrDrlTBOeumtgJ" : {
"nama" : "ilham"
},
"-LyUJbPOGxThn7YrPvva" : {
"nama" : "faiz"
}
}
}

16. Pilih file data.json


17. Berhasil import data.

18. Ubah rules-nya, read dan write menjadi true.

19. Pilih project settings


20. Pada tab general, buat project android.

21. Masukkan nama package


22. Download google-services.json
23. Copy file google-services.json ke dalam folder app

24. Copy classpath ke build.gradle


25. Copy plugin goolgle-services ke app-build.gradle
26. Tambahkan package firebase_database: ^3.1.1 pada Flutter dependencies

27. Buat kelas Mahasiswa (mahasiswa.dart)


import 'package:firebase_database/firebase_database.dart';

class Mahasiswa {

String _id;
String _nama;

Mahasiswa(this._id,this._nama);

String get nama => _nama;

String get id => _id;

Mahasiswa.fromSnapshot(DataSnapshot snapshot) {
_id = snapshot.key;
_nama = snapshot.value['nama'];
}
}

28. Buat kelas DatabaseCrud (database_crud.dart)


a. Buat variabel dan object baru dari firebase database
class DatabaseCrud {

//A Firebase reference represents a particular location in your Database


and
// can be used for reading or writing data to that Database location.
//This class is the starting point for all Database operations.
// After you've initialized it with a URL, you can use it to read data,
write data, and to create new DatabaseReferences.
DatabaseReference _counterRef;
DatabaseReference _userRef;

//The subscription provides events to the listener, and holds the


callbacks used to handle the events.
// The subscription can also be used to unsubscribe from the events, or to
temporarily pause the events from the stream.
StreamSubscription<Event> _counterSubscription;
StreamSubscription<Event> _messagesSubscription;

//The entry point for accessing a Firebase Database.


// You can get an instance by calling getInstance().
// To access a location in the database and read or write data, use
getReference()
FirebaseDatabase database = new FirebaseDatabase();

//increment variable x+=1


int _counter;

//Instances of DatabaseError are passed to callbacks when an operation


failed.
// They contain a description of the specific error that occurred.
DatabaseError error;

//create new instance based on its own class


static final DatabaseCrud _instance = new DatabaseCrud.internal();

DatabaseCrud.internal();

//A factory interface that also reports the type of the created objects.
//class contstructor
factory DatabaseCrud() {
return _instance;
}

//initState

b. Inistate
void initState() {

//get database ref with child = counter


//method 1 - Demonstrates configuring to the database using a file
_counterRef = FirebaseDatabase.instance.reference().child('counter');

//get database ref with child = user


//method 2 - Demonstrates configuring the database directly
_userRef = database.reference().child('user');

//print value of key = counter


database.reference().child('counter').once().then((DataSnapshot snapshot)
{
print('Connected to second database and read ${snapshot.value}');
});
//allow firebase to save data locally
//automatically stores the data offline when there is no internet
connection.
// When the device connects to the internet, all the data will be pushed
to the realtime database
database.setPersistenceEnabled(true);
database.setPersistenceCacheSizeBytes(10000000);
_counterRef.keepSynced(true);
_counterSubscription = _counterRef.onValue.listen((Event event) {
error = null;
_counter = event.snapshot.value ?? 0;
}, onError: (Object o) {
error = o;
});
}

//getError
//getCounter
//getAllUser
//dispose

c. Get Function
//getError
DatabaseError getError() {
return error;
}

//getCounter
int getCounter() {
return _counter;
}

//getAllUser
DatabaseReference getUser() {
return _userRef;
}

//dispose
void dispose() {
_messagesSubscription.cancel();
_counterSubscription.cancel();
}

d. deleteUser
void deleteUser(Mahasiswa user) async {
await _userRef.child(user.id).remove().then((_) {
print('Transaction committed.');
});
}

e. addUser
//addUser
addUser(Mahasiswa user) async {
final TransactionResult transactionResult =
await _counterRef.runTransaction((MutableData mutableData) async {
mutableData.value = (mutableData.value ?? 0) + 1;

return mutableData;
});

if (transactionResult.committed) {
_userRef.push().set(<String, String>{
"nama": "" + user.nama
}).then((_) {
print('Transaction committed.');
});
} else {
print('Transaction not committed.');
if (transactionResult.error != null) {
print(transactionResult.error.message);
}
}
}

f. updateUser
//updateUser
void updateUser(Mahasiswa user) async {
await _userRef.child(user.id).update({
"nama": "" + user.nama
}).then((_) {
print('Transaction committed.');
});
}

29. Code beranda.dart


a. Core
import 'package:flutter/material.dart';
import 'package:firebase_implementation/database_crud.dart';

class Beranda extends StatefulWidget {


@override
_MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<Beranda> {

bool _anchorToBottom = false;


// instance of util class
DatabaseCrud databaseUtil;

//inistate

//dispose

//showUser

//getShortName

//deleteUser

//showEditWidget

@override
Widget build(BuildContext context) {
// TODO: implement build
return null;
}
}

b. Widget build
@override
Widget build(BuildContext context) {
// it will show title of screen
Widget _buildTitle(BuildContext context) {
return new InkWell(
child: new Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'Data User',
style: new TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
),
);
}
//It will show new user icon
List<Widget> _buildActions() {
return <Widget>[
new IconButton(
icon: const Icon(
Icons.group_add,
color: Colors.white,
), // display pop for new entry
onPressed: () => null,//showEditWidget(null, false)
),
];
}

return new Scaffold(


appBar: new AppBar(
title: _buildTitle(context),
actions: _buildActions(),
),

// Firebase predefile list widget. It will get user info from firebase
database
body: new FirebaseAnimatedList(
key: new ValueKey<bool>(_anchorToBottom),
query: databaseUtil.getUser(),
reverse: _anchorToBottom,
sort: _anchorToBottom
? (DataSnapshot a, DataSnapshot b) => b.key.compareTo(a.key)
: null,
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
return new SizeTransition(
sizeFactor: animation,
child: showUser(snapshot),
);
},
),
);
}

c. showUser
//It will display a item in the list of users.
Widget showUser(DataSnapshot res) {
Mahasiswa user = Mahasiswa.fromSnapshot(res);

var item = new Card(


child: new Container(
child: new Center(
child: new Row(
children: <Widget>[
new CircleAvatar(
radius: 30.0,
child: new Text(getShortName(user)),
backgroundColor: const Color(0xFF20283e),
),
new Expanded(
child: new Padding(
padding: EdgeInsets.all(10.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
user.nama,
// set some style to text
style: new TextStyle(
fontSize: 20.0, color: Colors.lightBlueAccent),
),
],
),
),
),
new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new IconButton(
icon: const Icon(
Icons.edit,
color: const Color(0xFF167F67),
),
onPressed: () => null,
),
new IconButton(
icon: const Icon(Icons.delete_forever,
color: const Color(0xFF167F67)),
onPressed: () => null,
),
],
),
],
),
),
padding: const EdgeInsets.fromLTRB(10.0, 0.0, 0.0, 0.0)),
);

return item;
}

d. getShortName
//Get first letter from the name of user
String getShortName(Mahasiswa user) {
String shortName = "";
if (!user.nama.isEmpty) {
shortName = user.nama.substring(0, 1);
}
return shortName;
}

e. deleteUser
//Delete a entry from the Firebase console.
deleteUser(Mahasiswa user) {
setState(() {
databaseUtil.deleteUser(user);
});
}
//call delete function =
new IconButton(
icon: const Icon(Icons.delete_forever,
color: const Color(0xFF167F67)),
onPressed: () => deleteUser(user),
),

f. showEditWidget
//showEditWidget
showEditWidget(Mahasiswa user, bool isEdit) {
showDialog(
context: context,
builder: (BuildContext context) =>
new CrudDialog().buildAboutDialog(context, this, isEdit, user),
);
}

//implements AddUserCallBack in MyHomePageState


class _MyHomePageState extends State<Beranda> implements AddUserCallback

g. addUser
@override // Call util method for add user information
void addUser(Mahasiswa user) {
setState(() {
databaseUtil.addUser(user);
});
}

h. updateUser
i.
@override // call util method for update old data.
void update(Mahasiswa user) {
setState(() {
databaseUtil.updateUser(user);
});
}

j. dispose()
@override
void dispose() {
super.dispose();
databaseUtil.dispose();
}

k. iniState
@override
void initState() {
super.initState();
databaseUtil = new DatabaseCrud();
databaseUtil.initState();
}

30. Code main.dart


import 'package:flutter/material.dart';
import 'package:flutter_app/beranda.dart';
void main() {
runApp(new MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(
primaryColor: const Color(0xFF02BB9F),
primaryColorDark: const Color(0xFF167F67),
accentColor: const Color(0xFF167F67),
),
debugShowCheckedModeBanner: false,
title: 'Firebase',
home: new Beranda(),
);
}
}

31. Code crud_dialog.dart


a. Core
import 'package:flutter/material.dart';
import 'package:firebase_implementation/mahasiswa.dart';

class CrudDialog {
final teName = TextEditingController();
Mahasiswa user;

//buildAboutDialog
//linkStyle
//buildAboutDialog
//getTextField
//getAppBorderButton
//getData
//onTap
}
//Call back of user dashboad
abstract class AddUserCallback {
void addUser(Mahasiswa user);

void update(Mahasiswa user);


}

b. Linkstyle
//linkStyle
static const TextStyle linkStyle = const TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
);
c. buildAboutDialog
//buildAboutDialog
Widget buildAboutDialog(BuildContext context,
AddUserCallback _myHomePageState, bool isEdit, Mahasiswa user) {
if (user != null) {
this.user = user;
teName.text = user.nama;
}

return new AlertDialog(


title: new Text(isEdit ? 'Edit detail!' : 'Add new user!'),
content: new SingleChildScrollView(
child: new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
getTextField("Nama", teName),
new GestureDetector(
onTap: () => onTap(isEdit, _myHomePageState, context),
child: new Container(
margin: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
child: getAppBorderButton(isEdit ? "Edit" : "Add",
EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0)),
),
),
],
),
),
);
}

d. getTextField
//getTextField
Widget getTextField(
String inputBoxName, TextEditingController inputBoxController) {
var loginBtn = new Padding(
padding: const EdgeInsets.all(5.0),
child: new TextFormField(
controller: inputBoxController,
decoration: new InputDecoration(
hintText: inputBoxName,
),
),
);

return loginBtn;
}

e. getAppBorderButton
//getAppBorderButton
Widget getAppBorderButton(String buttonLabel, EdgeInsets margin) {
var loginBtn = new Container(
margin: margin,
padding: EdgeInsets.all(8.0),
alignment: FractionalOffset.center,
decoration: new BoxDecoration(
border: Border.all(color: const Color(0xFF28324E)),
borderRadius: new BorderRadius.all(const Radius.circular(6.0)),
),
child: new Text(
buttonLabel,
style: new TextStyle(
color: const Color(0xFF28324E),
fontSize: 20.0,
fontWeight: FontWeight.w300,
letterSpacing: 0.3,
),
),
);
return loginBtn;
}

f. getData
//getData
Mahasiswa getData(bool isEdit) {
return new Mahasiswa(isEdit ? user.id : "", teName.text);
}

g. onTap
//onTap
onTap(bool isEdit, AddUserCallback _myHomePageState, BuildContext context) {
if (isEdit) {
_myHomePageState.update(getData(isEdit));
} else {
_myHomePageState.addUser(getData(isEdit));
}

Navigator.of(context).pop();

You might also like