Day 30 : Firebase

Day 30 : Firebase Cover Image

สวัสดีครับ บทความนี้เป็นบทความที่ 30 บทความสุดท้ายแล้วนะครับ ใครที่ติดตามอ่านอยู่ก็ขอขอบคุณมากเลยครับ :D

สำหรับบทความทั้งหมด อ่านได้จากด้านล่างครับ

สำหรับวันนี้ขอนำเสนอเรื่อง Firebase

Firebase

Firebase เป็น Real Time App Platform คือให้บริการ API สำหรับการส่งข้อมูลแบบ Real Time รองรับหลาย Platform สามารถเขียนได้หลายภาษา รายละเอียดเพิ่มเติม อ่านได้ที่เว็บ Firebase เลยครับ

สำหรับบทความนี้ จะใช้ Firebase API มาใช้ในการทำแอพ Chat บน Android นะครับ เป็นแอพง่ายๆ มาเริ่มทำกันเลยดีกว่า

Register

เริ่มแรก ต้องทำการสมัคร Firebase ซะก่อน การสมัครไม่ยุ่่งยากเลย ขอข้ามส่วนนี้ไปเลยละกันครับ เมื่อสมัครเสร็จเรียบร้อย ทุกคนจะมีหน้า Dashboard เป็นของตนเอง

Dashboard

แต่ว่าเมื่อสมัครเข้ามาแล้ว จะมี Guide ให้เราอ่านมากมายครับ เช่น Example, Tutorial, Quick Start, API Docs ก็อ่านประกอบๆ ด้วยก็ดีนะครับ

กดสร้าง App ใหม่ได้เลยครับ เมื่อสร้างเสร็จ เราจะได้หน้าไว้จัดการข้อมูล โดยเป็น https://ชื่อแอพที่ตั้ง.firebaseio.com เช่นของผมเป็น https://ahoychat.firebaseio.com/ หน้าตาจัดการ Firebase ของเราจะเป็นประมาณนี้

Firebase2

ทีนี้ในส่วนหน้าเว็บ ก็หยุดไว้แค่นี้ครับ สร้างแอพมาแล้ว ต่อไปก็เป็นการติดตั้ง Firebase Client เพื่อใช้ในแอพ Android

Installation

ขั้นตอนการติดตั้ง เปิดไฟล์ build.gradle ขึ้นมา แล้วเพิ่ม dependencies ลงไปดังนี้

dependencies {
    compile 'com.firebase:firebase-client:1.0.16+'
}

กด Sync Gradle เป็นอันเรียบร้อย

อย่าลืมเพิ่ม permission INTERNET ในไฟล์ AndroidManifest.xml ด้วยนะครับ

<uses-permission android:name="android.permission.INTERNET" />

Usage

การใช้งาน Firebase เบื้องต้นนะครับ เริ่มแรกต้องทำการสร้าง ออปเจ็ค reference ให้มันก่อน โดยใช้ URL ที่ได้ตอนเราสร้างแอพผ่านหน้าเว็บอะครับ

Firebase firebase = new Firebase("https://<your-firebase>.firebaseio.com/");

Firebase จะเก็บข้อมูลทั้งหมดในรูปแบบ JSON นะครับ

การเซฟข้อมูล

ตัวอย่างการเซฟข้อมูล ตามโค๊ดด้านล่าง

firebase.child("message").setValue("Do you have data? You'll love Firebase.");

การอ่านข้อมูล

การอ่านข้อมูล จะใช้ Listener เข้ามาช่วยครับ เมื่อมีข้อมูลถูกเพิ่มเข้ามา ก็จะส่ง event กลับมาครับ ตามข้างล่างนี้

firebase.child("message").addValueEventListener(new ValueEventListener() {

  @Override
  public void onDataChange(DataSnapshot snapshot) {
    System.out.println(snapshot.getValue());  //prints "Do you have data? You'll love Firebase."
  }

  @Override public void onCancelled(FirebaseError error) { }

});

โค๊ดทั้งหมดนี้ ผมเอามาจาก Docs เลยนะครับ จริงๆ อ่านจาก Docs น่าจะเข้าใจง่ายกว่านะ มาลองเริ่มทำโปรเจ็คเล็กๆกันดูครับ :D

Create Project

หลักจากที่เราทำการเพิ่ม dependencies เรียบร้อยแล้ว ต่อมา สร้างเลเอาท์ก่อนเลยครับ จะใช้เลเอาท์ไฟล์เดียวนะครับ สมมติชื่อ activity_firebase.xml ภายในเลเอาท์ประกอบไปด้วย

  • ListView : สำหรับแสดงข้อความแชต
  • EditText : สำหรับพิมพ์ข้อความ
  • ImageButton : สำหรับกดเมื่อต้องการส่งข้อความ
<?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="match_parent">

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/linear"
        android:id="@+id/list_view" />

    <LinearLayout android:id="@+id/linear"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:layout_alignParentBottom="true"
                  android:orientation="horizontal">

        <EditText
            android:id="@+id/message"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:layout_weight="1"
            android:lines="1"
            android:inputType="textShortMessage"
            android:singleLine="true" />

        <ImageButton
            android:id="@+id/button_send"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:src="@android:drawable/ic_menu_send" />
    </LinearLayout>

</RelativeLayout>

ต่อมาสร้างไฟล์ FirebaseActivity.java ขึ้นมา ดังนี้

package com.devahoy.learn30androidlibraries.day30;

import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;

import com.devahoy.learn30androidlibraries.R;
import com.firebase.client.ChildEventListener;
import com.firebase.client.DataSnapshot;
import com.firebase.client.Firebase;
import com.firebase.client.FirebaseError;
import com.firebase.client.Query;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

public class FireBaseActivity extends ActionBarActivity {

    private static final String AHOY_CHAT_URL = "https://ahoychat.firebaseio.com";
    private List<String> mChats = new ArrayList<String>();
    private ListView mListView;
    private ArrayAdapter<String> mAdapter;
    private ImageButton mButtonSend;
    private EditText mMessage;

    private Firebase mFirebase;
    private String mUsername;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Random r = new Random();
        mUsername = "AhoyUser" + r.nextInt(1000);

        setContentView(R.layout.day30_activity_firebase);

        mButtonSend = (ImageButton) findViewById(R.id.button_send);
        mMessage = (EditText) findViewById(R.id.message);
        mListView = (ListView) findViewById(R.id.list_view);
        mListView.setBackgroundColor(Color.parseColor("#26B895"));

        mFirebase = new Firebase(AHOY_CHAT_URL).child("chat");

        queryData();

        mButtonSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendMessage();
            }
        });
    }

    private void sendMessage() {
//        Chat chat = new Chat(mMessage.getText().toString(), mUsername);

        Map<String, Object> chat = new HashMap<String, Object>();
        chat.put("owner", mUsername);
        chat.put("message", mMessage.getText().toString());

        mFirebase.push().setValue(chat);
        mMessage.setText("");
    }

    private void queryData() {
        Query query = mFirebase.limit(10);

        query.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                Map<String, Object> newPost = (Map<String, Object>) dataSnapshot.getValue();
                String owner = newPost.get("owner").toString();
                String message = newPost.get("message").toString();

                mChats.add(0, owner + " Say: " + message);

                if (mAdapter == null) {

                    mAdapter = new ArrayAdapter<String>(getApplicationContext(),
                            android.R.layout.simple_list_item_1, mChats);

                    mListView.setAdapter(mAdapter);
                }
                mAdapter.notifyDataSetChanged();
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                mAdapter.notifyDataSetChanged();
            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {

            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onCancelled(FirebaseError firebaseError) {

            }
        });
    }
}

จากโค๊ดด้านบน เริ่มไล่ตั้งแ่ต่ onCreate() เลยนะครับ ภายในเมธอดนี้เราก็ทำการ findView ให้หมด จากนั้นอ้าง Reference ของ Firebase ด้วย new Firebase("url").child("chat"); ใส่ url ของเรา และอ้างอิง child ที่ชือว่า chat จากนั้นก็มี call เมธอด queryData() ในส่วนนี้จะเป็นการ Query เพื่อเอาข้อมูลจาก Firebase มาแสดง เมธอด sendMessage() ทำการรับข้อความจาก EditText ทีเรากรอกลงไป จากนั้นก็ใช้ Map<String, Object> เพื่อทำการแมพ key, value ชื่อ owner และ message เพื่อส่งไปยัง Firebase โดยใช้คำสั่ง mFirebase.push().setValue(chat); เพื่อส่งข้อมูล จริงๆ ส่วนนี้จะใช้เป็นคลาส Model ก็ได้นะครับ ตามที่ผม comment ไว้ ส่วนคลาส Chat ดูได้จากนี้

ต่อมาที่เมธอด queryData() จะเห็นคำสั่ง Query query = mFirebase.limit(10); คือการเรียกข้อมูลจาก Firebase มาแสดง จำกัดแค่ 10 ค่า จากนั้นใช้ addChildEventListener โดยมี Listener เป็น ChildEventListener() ส่วนที่เราสนใจคือ เมธอด onChildAdded() ในส่วนนี้จะ call เมื่อมีการเพิ่มข้อมูลใน Firebase ทั้งจากแอพของเรา จากทางบราวเซอร์ หรือจากเครื่องอื่นๆ ที่ใช้แอพนี้ ฉะนั้นส่วนนี้ก็เลยเป็นส่วนที่ผมเอาไว้ สร้าง ListView ครับ

การ getValue() จาก Firebase ในเมธอด onChildAdded() จะมี DataSnapshot ส่งมาด้วย ตัวนี้ เราจะได้ค่าจาก คำสั่งนี้

Map<String, Object> newPost = (Map<String, Object>) dataSnapshot.getValue();
String owner = newPost.get("owner").toString();
String message = newPost.get("message").toString();

คือหา key ที่มีคำว่า owner และ message ซึ่งเป็นคีย์เดียวกันกับตอนที่เรากด sendData ส่วนที่เหลือก็เป็นการสร้าง ArrayAdapter และ setAdapter ธรรมดาครับ

ลองดูใน Browser ก็เป็นข้อมูลชนิดเดียวกัน

ผลลัพธ์ที่ได้ ก็ประมาณนี้

Result

สรุป

ตัว Firebase ก็น่าสนใจไม่น้อยเลย จำได้ว่าเคยได้ยินครั้งแรก รู้สึกจะในงาน ์ng-conf เห็นโชว์การทำ 3-Data Binding แต่ว่าก็ไม่ได้ลองใช้อะไรเท่าไหร่ มาวันนี้ก็เลยลองทำแอพเล่นๆ ด้วย Android ซะเลย หากใครต้องการทำแอพแนว Real Time เช่นพวกแอพแชต หรือว่าแนว Co-Work หรือเอามาทำเกมแข่งกันแบบ 1-1 ก็น่าจะได้ รู้สึกเคยเห็นตัวอย่างอยู่เหมือนกัน Firebase น่าจะเหมาะสมเลย อีกอย่าง ฟรีด้วยครับ (แต่ว่า Limit 50 Max Connections)

หมดแล้ว 30 วัน บอกตรงๆว่าเหนือ่ยมากๆ แถมนอนดึกทุกวันเลย บางวัน หลักจากเลิกงาน แทบไม่อยากเปิดคอม พอหัวถึงหมอนก็หลับเลย โอเค ถือว่า Challenge Complete แล้ว หลังจากนี้จะได้มีเวลาให้กับโปรเจ็คเกมของตัวเองซะที ไม่นานเกินรอ :D

References

Chai Chai Phonbopit : Software Engineer @Nextzy • ผู้ชายธรรมดาๆ ที่ชื่นชอบ Android, JavaScript (Node.js) และ Open Source มีงานอดิเรกเป็น Acoustic Guitar และ Football

บทความล่าสุด