Menjadi “Full Stack Developer” dengan Firebase Realtime Database

Ade Rifaldi
Blackdesk
Published in
7 min readMar 23, 2017
Simple Todo List App use Firebase Realtime Database

Saya sering mendengar tentang kisah seorang developer yang mampu membuat sebuah aplikasi dinamis dari hulu ke hilir seorang diri, Full stack developer. Sebuah istilah yang super cool untuk merepresentasikan seorang developer yang mampu membuat sebuah aplikasi dinamis seorang diri, dimana umumnya bisa diselesaikan oleh setidaknya dua sampai tiga orang.

Saya sempat merasa takjub dengan istilah tersebut, hingga akhirnya saya mengenal Azure Mobile Service dan Firebase Realtime Database (FRD). Kedua platform tersebut bisa membantu saya khususnya dan pembaca pada umumnya menjadi serupa hampir tak sama dengan full stack developer sesungguhnya.

Di tulisan ini, saya akan membahas khusus ke Firebase Realtime Database (FRD), sebuah cloud hosted database yang sudah mendukung multiplatform: Android, iOS, dan Web dan seperti namanya: bersifat realtime. Berbeda dengan database yang umumnya digunakan (berbasis tabel), database pada FRD berbasis JSON. Jadi, data-data dikumpulkan dalam format JSON dengan multiple node. Kemudian, dalam merencanakan sebuah database yang akan dibuat, kita harus terlebih dahulu menyiapkan struktur JSON database kita, yaitu apa yang disebut sebagai Realtime Database Rules.

Untuk overview tentang Firebase Realtime Database, silahkan kunjungi laman berikut https://firebase.google.com/docs/database/

Mari mulai dan rasakan bagaimana membangun sebuah aplikasi Simple Todo dengan FRD.

Overview:

Project Contoh: Simple Todo List App
Spesifikasi: Create, Read, Update, Delete Todo

Todo:
Configure Project
1.Create Android Project
2. Create Firebase Project
3. Add Android App
4. Add Package Name
5. Add google-service.json to Android Project
6. Add google playstore dependency
7. Add FRD dependency to Android Project
8. Add FRD Rules

Build App
1. Implement UI: list & form input in one page
2. Read Single Data from FRD
3. Create Class Model: Todo
4. Add Todo
5. View Todo List
6. Update Todo
7. Delete Todo

Configure Project

1. Create Android Studio Project

Hal pertama yang harus dilakukan sudah pasti: Create new Android Project. Kemudian, pastikan project yang telah dibuat dapat dijalankan (di-run) di device atau emulator.

2. Create Firebase Project

Kunjungi https://console.firebase.google.com/ dan Create New Project

Create Firebase Project

3. Add Android App

Create Android Project

4. Add Package Name to Firebase Project.

Isi dengan nama package dari Android Project yang sudah dibuat.

Add Package Name Android Project

5. Download google-service.json & add to Android Project

Open App Setting
Download google-service.json

Add file google-service.json pada folder app.

Add google-service.json

6. Add google playstore dependency

Buka file build.gradle (Project: <nama project>) dan add google playstore dependency pada bagian dependencies.

dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'com.google.gms:google-services:3.0.0'
}

7. Add Firebase Realtime Database dependency

Buka file build.gradle (Module: app). pada bagian dependencies, add

compile 'com.google.firebase:firebase-database:9.6.1'

kemudian, aktifkan google service dan letakan pada bagian terbawah (di luar bagian dependencies)

apply plugin: 'com.google.gms.google-services'

Setelah itu, lakukan Sync Gradle.

8. Kembali ke firebase console untuk mengatur Database Rules

Masuk ke menu: Database — Rules kemudian, masukan Rules di bawah ini:

{
"rules": {
".read": true,
".write": true,
"todos": {
"$todo": {
"id": {
".validate": "newData.isString()"
},
"item": {
".validate": "newData.isString()"
},
"is_done": {
".validate": "newData.isBoolean()"
}
}
}
}
}

Jangan lupa untuk Publish.

Add Database Rules

Bagian Configure Project sudah selesai sebagai langkah awal.

CRUD

Untuk selingan sebelum melanjutkan ke bagian Build App, saya jelaskan sedikit tentang operasi-operasi (CRUD) yang ada pada Firebase Realtime Database.

Insert (Create)

Untuk insert data, kita bisa menggunakan method setValue(). FRD telah mendukung tipe data yang cukup beragam: String, Long, Double, Boolean, Map<String, Object>, List<Object>.

private DatabaseReference mFirebaseDatabase;
private FirebaseDatabase mFirebaseInstance;
mFirebaseInstance = FirebaseDatabase.getInstance();
mFirebaseDatabase = mFirebaseInstance.getReference("app_title");
mFirebaseDatabase.setValue("Simple Todo List");

Selain itu, kita juga bisa menggunakan class model yang kita buat dengan catatan variable-variable pada class model sesuai dengan properti-properti (node-node) pada rules database yang telah dibuat. jika tidak, maka akan muncul property Json baru pada database.

contoh:

public class Todo {

public String id, item;
public boolean is_done;

public Todo(){
}

public Todo(String id, String item, boolean is_done) {
this.id = id;
this.item = item;
this.is_done = is_done;
}
}
private DatabaseReference mFirebaseDatabase;
private FirebaseDatabase mFirebaseInstance;
mFirebaseInstance = FirebaseDatabase.getInstance();
mFirebaseDatabase = mFirebaseInstance.getReference("todos");
private void insertTodo(String todoId, String todoItem, boolean isDone){

Todo todo = new Todo(todoId, todoItem, isDone);
mFirebaseDatabase.child(todoId).setValue(todo);
}

View (Read)

Untuk Read data, kita harus menambahkan ValueEventListener() ke DatabaseReferences. Event tersebut akan dieksekusi setiap ada perubahan data secara realtime. Tepatnya kita dapat melakukannya pada onDataChange().

contoh:

private FirebaseDatabase mFirebaseInstance;mFirebaseInstance = FirebaseDatabase.getInstance();mFirebaseInstance.getReference("app_title").addValueEventListener(
new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.e(TAG, "App title updated");
String appTitle = dataSnapshot.getValue(String.class);
getSupportActionBar().setTitle(appTitle);
}

@Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.e(TAG, "Failed to read app title value.", error.toException());
}
});

Update

Untuk update data, hampir sama dengan Insert data. hanya saja, kita perlu memberitahu item data mana yang ingin kita update menggunakan properti child.

contoh:

private void updateTodo(String id, boolean isDone){
mFirebaseDatabase.child(id).child("is_done").setValue(isDone);
}

Delete

Untuk delete data, masih sama. yaitu, menggunakan setValue null.

contoh:

public void deleteItem(String id){
mFirebaseDatabase.child(id).setValue(null);
}

Jika ingin mengetahui CRUD Operation yang lebih kompleks. Bisa dilihat pada dokumentasi berikut https://firebase.google.com/docs/database/android/lists-of-data

Langkah selanjutnya setelah Configure Project adalah Build App

Build App

1. Implement UI: list & form input in one page: activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorWhite"
tools:context="com.radyalabs.todolistusefrd.activity.MainActivity">

<RelativeLayout
android:id="@+id/containerAddTodo"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true">

<EditText
android:id="@+id/edtTodo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:imeOptions="actionDone"
android:textColor="@color/colorPrimary"
android:textColorHint="@color/colorAccent"
android:textSize="17sp"
android:inputType="text"
android:hint="Write todo here"
android:background="@color/colorWhite"/>

</RelativeLayout>

<View
android:id="@+id/line"
android:layout_above="@id/containerAddTodo"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/colorPrimary"/>

<RelativeLayout
android:layout_above="@id/line"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/listTodo"
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"/>

<ProgressBar
android:id="@+id/loading"
android:visibility="gone"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_centerInParent="true"/>

<TextView
android:id="@+id/txtEmptyInfo"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="17sp"
android:layout_centerInParent="true"
android:textColor="@color/colorAccent"
android:text="There is no todo"/>
</RelativeLayout>

</RelativeLayout>
activity_main.xml

2. Read Single Data from FRD

Bisa dilihat bahwa App Title menggunakan nama project yang telah diinisialisai ketika Create new Project. Pada project sample yang telah saya buat, App title akan berubah sesuai dengan value dari “app_title” yang ada pada Firebase Database.

berikut ini adalah kode yang saya gunakan:

3. Create Class Model: Todo

Seperti kita ketahuin sebelumnya, bahwa insert data ke database bisa menggunakan class model (Todo.java) dengan catatan: nama variable harus sesuai dengan nama node yang ada pada database rules. Maka itu, saya membuat sebuah class model Todo.java sebagai berikut:

Todo.java

sesuai dengan rules pada object node todos

Firebase Database Rules

4. View Todo List

Ada beberapa hal yang perlu dilakukan untuk menampilkan data todos dalam bentuk list. Pada project ini saya menggunakan RecyclerView dimana setiap item todo memiliki spesifikasi: bisa ditandai apakah sudah dikerjakan atau belum (is_done) dan bisa dihapus dengan cara melakukan long tap pada setiap item todo.

a. Membuat Item View: item_todo.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<ImageView
android:id="@+id/doneTodo"
android:layout_width="56dp"
android:layout_height="56dp"
android:padding="16dp"
android:src="@drawable/not_done"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"/>

<TextView
android:id="@+id/todoItem"
android:layout_toLeftOf="@id/doneTodo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/colorPrimary"
android:text="Todo"
android:textSize="17sp"
android:padding="16dp"
android:layout_centerVertical="true" />

</RelativeLayout>
item_todo.xml

b. TodoListAdapter.java
Dua spesifikasi item todo diimplementasi pada RecyclerView Adapter ini dengan memasang onLongClick pada itemView dan onClickListener pada ImageView (doneTodo).

package com.radyalabs.todolistusefrd.adapter;

import android.app.Activity;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.TextView;

import com.radyalabs.todolistusefrd.R;
import com.radyalabs.todolistusefrd.activity.MainActivity;
import com.radyalabs.todolistusefrd.model.Todo;

import java.util.ArrayList;

import butterknife.BindView;
import butterknife.ButterKnife;

public class TodoListAdapter extends RecyclerView.Adapter<TodoListAdapter.MyViewHolder> {

private ArrayList<Todo> data;
private LayoutInflater inflater;
private Context context;
private AdapterView.OnItemClickListener onItemClickListener;
private AdapterView.OnItemLongClickListener onItemLongClickListener;

public TodoListAdapter(Context context) {
this.context = context;
inflater = LayoutInflater.from(context);
this.data = new ArrayList<>();
}

public void setOnItemClickListener(AdapterView.OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}

public void setOnItemLongClickListener(AdapterView.OnItemLongClickListener onItemLongClickListener) {
this.onItemLongClickListener = onItemLongClickListener;
}

public ArrayList<Todo> getData() {
return data;
}


@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = (LayoutInflater) parent.getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
View view = layoutInflater.inflate(R.layout.item_todo, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}

@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
final Todo todo = data.get(position);
holder.position = position;

final long identity = System.currentTimeMillis();
holder.identity = identity;

if (holder.identity == identity){
if (todo.is_done){
holder.doneTodo.setImageResource(R.drawable.done);
}else {
holder.doneTodo.setImageResource(R.drawable.not_done);
}

holder.todoItem.setText(todo.item);

holder.doneTodo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

if (todo.is_done){
((MainActivity)context).setDone(todo.id, false);
}else {
((MainActivity)context).setDone(todo.id, true);
}

}
});
}

}

@Override
public int getItemCount() {
return data.size();
}

class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, AdapterView.OnLongClickListener{
int position;
long identity;

@BindView(R.id.todoItem) TextView todoItem;
@BindView(R.id.doneTodo) ImageView doneTodo;

public MyViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);

ButterKnife.bind(this, itemView);

}

@Override
public void onClick(View v) {
if (onItemClickListener != null){
onItemClickListener.onItemClick(null, v, position, 0);
}
}


@Override
public boolean onLongClick(View v) {
if (onItemLongClickListener != null){
onItemLongClickListener.onItemLongClick(null, v, position, 0);
}
return false;
}
}
}

c. menampilkan list of Todo ke RecycleView

private void loadTodoList(){
mFirebaseDatabase.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
loading.setVisibility(View.VISIBLE);
adapter.getData().clear();

if (dataSnapshot.getChildrenCount() != 0){
txtEmptyInfo.setVisibility(View.GONE);

for (DataSnapshot data : dataSnapshot.getChildren()){
Todo todo = data.getValue(Todo.class);
adapter.getData().add(todo);
adapter.notifyItemInserted(adapter.getData().size() - 1);
}
adapter.notifyDataSetChanged();

}else {
txtEmptyInfo.setVisibility(View.VISIBLE);
}

loading.setVisibility(View.GONE);
adapter.notifyDataSetChanged();

}

@Override
public void onCancelled(DatabaseError databaseError) {

}
});
}

Demikian artikel sesi berbagi ini. Semoga bisa bermanfaat.

Sedikit catatan, pada project sample ini saya sudah melakukan perubahan pada google-service.json. Jadi, silahkan untuk meng-generate google-service.json sendiri

Referensi:
Android working with Firebase Realtime Database
http://www.androidhive.info/2016/10/android-working-with-firebase-realtime-database/

Sample

Project Sample bisa didownload / clone di github saya di sini.

--

--