Nội dung:

  • Giới thiệu Firebase Realtime DB
  • Những đặc điểm nổi bật của Firebase Realtime DB
  • Firebase Realtime DB Rule
  • Chạy ứng dụng Android
  • Kết luận
  • Tài liệu tham khảo

I. Giới thiệu Firebase Realtime Database

Các bạn có thể than khảo qua 2 phần trước của loạt bài về Firebase

Firebase lưu trữ dữ liệu database dưới dạng JSON và thực hiện đồng bộ database tới tất cả các client theo thời gian thực và vẫn available khi app của bạn trong trạng thai offline (điển hình như các ứng dụng chat). Cụ thể hơn là bạn có thể xây dựng được client đa nền tảng (cross-platform client) và tất cả các client này sẽ cùng sử dụng chung 1 database đến từ Firebase và có thể tự động cập nhật mỗi khi dữ liệu trong database được thêm mới hoặc sửa đổi.

Ngoài ra Firebase còn cho phép bạn phân quyền một các đơn giản bằng cú pháp tương tự như javascript.

II. Những đặc điểm nổi bật của Firebase Realtime DB

![](https://drive.google.com/uc?id=0B05rqFCwNCjkeHc4U19LSTAycDQ&export=download)

Chi tiết:

  • Cơ sở dữ liệu NoSQL.
  • Dữ liệu được lưu trữ ở local trong khi offline và thực hiện đồng bộ khi dc kết nối
  • Khi thiết bị khôi phục kết nối, Realtime DB sẽ tự động đồng bộ hóa các thay đổi trong dữ liệu local với các bản cập nhật từ xa xảy ra khi client ở trạng thái offline, Tự động tích hợp nếu có xung đột.
  • Realtime Database API được thiết kế để cho phép hoạt động chỉ có thể được thực hiện trong một thời gian ngắn.
  • Firebase Realtime Database Security Rules cung cấp một ngôn ngữ quy tắc dựa trên biểu thức linh hoạt xác định cấu trúc dữ liệu và thời gian để cho phép đọc và ghi dữ liệu.

1. Cơ sở dữ liệu NoSQL.

Firebase realtime database lưu trữ dữ liệu theo định dạng JSON. Về cơ bản thì toàn bộ dữ liệu là một JSON tree lớn cùng với nhiều điểm node. Nên khi bạn xây dựng dữ liệu, bạn cần chuẩn bị một cấu trúc json để dễ dàng cho việc truy cập tránh việc các node con bị lồng nhau
Sau đây là ví dụ:

{
  "users": [
    {
      "name": "Ravi Tamada",
      "email": "ravi@androidhive.info",
      "address": "XXX, XXXX, 1234"
    }
  ],
  "posts": [
    {
      "id": 100,
      "author": "Ravi Tamada",
      "content": "This is awesome firebase realtime database...",
      "timestamp": "13892733894"
    }
  ]
}

2. Dữ liệu được lưu trữ ở local trong khi offline

Trong trường hợp offline vẫn có khả năng sử dụng FB Realtime database. Firebase có cơ chế đồng bộ sự sai khác data khi chuyển từ offline sang online. Nó tự động lưu trữ offline khi không có kết nối internet.
Xem thêm tại đây
Khi thiết bị khôi phục kết nối, Realtime DB sẽ tự động đồng bộ hóa các thay đổi trong dữ liệu local với các bản cập nhật từ xa xảy ra khi client ở trạng thái offline, Tự động tích hợp nếu có xung đột.

3. Thực hiện các thao tác CRUD

Trước khi vào ứng dụng android cụ thể, tôi muốn cung cấp cho bạn các thông tin cơ bản về thực hiện các thao tác CRUD trên cơ sở dữ liệu thời gian thực. Sau đó chúng ta sẽ kết hợp tất cả các khái niệm này với nhau để xây dựng một ứng dụng đơn giản với firebase realtime database. Các mã dưới đây cho phép bạn tham chiếu đến nút trên cùng của cơ sở dữ liệu JSON. Từ đây bạn cần phải sử dụng các tên nút con phải đi qua các nút khác.
private DatabaseReference mDatabase;
mDatabase = FirebaseDatabase.getInstance().getReference();
3.1 Inserting Data

Để chèn dữ liệu, bạn có thể sử dụng phương thức setValue () trên đường dẫn tham chiếu cơ sở dữ liệu. Điều này sẽ tạo ra hoặc cập nhật giá trị trên đường dẫn được cung cấp. Ví dụ dưới đây thêm vào một nút có tên là "artists" trên cây json ở mức đỉnh.

DatabaseReference databaseArtists;
databaseArtists = FirebaseDatabase.getInstance().getReference("artists");
databaseArtists .setValue("Something");

Realtime database chấp nhận nhiều loại dữ liệu: String, Long, Double, Boolean, Map, List để lưu trữ dữ liệu. Bạn cũng có thể sử dụng dữ liệu tùy biến của đối tượng để lưu trữ dữ liệu, điều này rất hữu dụng khi lưu trữ đối tượng vào database một cách trực tiếp.

Giả sử bạn muốn lưu trữ thông tin Artists vào database. Đầu tiên bạn cần tạo Artists model cùng với constructor rỗng và những thuộc tính khác.

public class Artist {
    String artistId;
    String artistName;
    String artistGenre;

    public Artist(){

    }
    public Artist(String artistId, String artistName, String artistGenre){
        this.artistId = artistId;
        this.artistName = artistName;
        this.artistGenre = artistGenre;
    }

    public String getArtistId() {
        return artistId;
    }

    public String getArtistName() {
        return artistName;
    }

    public String getArtistGenre() {
        return artistGenre;
    }
}

Mọi Artist cần một ID duy nhất, bạn có thể tạo ra một bằng cách gọi phương thức push () để tạo ra một nút trống rỗng, với khóa duy nhất. Sau đó, được tham chiếu đến nút 'artists' bằng phương thức child(). Cuối cùng sử dụng phương thức setValue() để lưu trữ dữ liệu artists.

// get a unique id using for push().getKey() method
// It will create a unique id as Artist ID
String id = databaseArtists.push().getKey();

// Create Artist Object
Artist artist = new Artist(id, name, genre);

// Save the Artist
databaseArtists.child(id).setValue(artist);

Bằng việc chạy đoạn code ở dưới, các nút người dùng mới sẽ được chèn vào database cùng với giá trị khóa duy nhất.

3.2. Reading Data

Để đọc dữ liệu, bạn cần đính kèm phương thức ValueEventListener() để tham chiếu database. Sự kiện này sẽ được kích hoạt bất cứ khi nào có sự thay đổi trong dữ liệu trong thời gian thực. Trong onDataChange(), bạn có thể thực hiện các phương thức mong muốn vào dữ liệu mới.
Dưới đây là sự kiện lắng nghe được kích hoạt bất cứ khi nào có sự thay đổi trong dữ liệu hồ sơ người dùng mà đã tạo ra trước đó.

    @Override
    protected void onStart(){
        super.onStart();

        databaseArtists.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {

                artistList.clear();

                for(DataSnapshot artistSnapshot : dataSnapshot.getChildren()){
                    Artist artist = artistSnapshot.getValue(Artist.class);
                    artistList.add(artist);
                }

                ArtistList adapter = new ArtistList(MainActivity.this, artistList);

                // attaching adapter to the listview
                listViewArtists.setAdapter(adapter);
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });
    }
3.3. Updating Data

Để cập nhật dữ liệu, bạn có thể sử dụng cùng phương pháp setValue() để passing giá trị mới. Bạn cũng có thể sử dụng phương thức updateChildren() để passing đường dẫn để cập nhật dữ liệu mà không làm ảnh hưởng đến các nút con khác.

Ví dụ, nếu bạn muốn cập nhật artists name, bạn có thể sử dụng đoạn code bên dưới

// get values to update
String name = editTextName.getText().toString().trim();

// Update the Artist name
databaseArtists.child(id).child("name").setValue(name );
3.4 Deleting Data

Để xóa dữ liệu, bạn có thể gọi phương thức removeValue() trong database reference. Bạn cũng có thể pass null để gọi phương thức setValue(), nó giống như phương thức xóa
Bạn có thể tìm hiểu nhiều hơn về CRUD thông qua tài liệu nâng cao tại đây

III. Firebase Realtime DB Rule

Firebase Rule cung cấp một cách xác định vai trò người dùng trong khi thực hiện các thao tác đọc và ghi. Các quy tắc này sẽ hoạt động một lớp bảo mật trên máy chủ trước khi thực hiện bất kỳ hoạt động CRUD nào. Theo mặc định, các quy tắc cho phép người dùng thực hiện thao tác đọc và ghi chỉ sau khi xác thực.
Các quy tắc dưới đây cho phép người dùng xác thực chỉ đọc hoặc ghi dữ liệu.

{
  "rules": {
    ".read": "auth != null",
    ".write": "auth != null"
  }
}

Dưới đây quy tắc cho phép mọi người đọc và ghi dữ liệu mà không cần xác thực.

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

Bạn cũng có thể sử dụng các quy tắc này để validate dữ liệu trước khi insert vào cơ sở dữ liệu. Ví dụ dưới đây các quy tắc xác nhận tên có ít hơn 50 ký tự và email là hợp lệ sử dụng biểu thức chính quy email.

{
    "rules": {
        ".read": true,
        ".write": true,
        "users": {
            "$user": {
                "name": {
                    ".validate": "newData.isString() && newData.val().length < 50"
                },
                "email": {
                    ".validate": "newData.isString() && newData.val().matches(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$/i)"
                }
            }
        }
    }
}

Bạn có thể tìm kiểu kỹ hơn về firebase realtime database rules tại đây.

IV. Chạy ứng dụng Android

1. Create firebase project

Điều đầu tiên bạn cần làm là vào https://firebase.google.com/ và tạo tài khoản để truy cập vào giao diện firebase console. Sau khi bạn truy cập vào giao diện console bạn có thể bắt đầu bằng cách tạo project đầu tiên của bạn.

2. Add android app

Cung cấp tên packge android app của bạn (của mình là com.phongnx.firebaserealtimedatabase), trong đó bạn sẽ tích hợp Firebase. Ở đây, file google-services.json sẽ được tải xuống khi bạn nhấn nút REGISTER APP.

3. Create a new project in Android Studio

Create a new project in Android Studio from File ⇒ New Project. Trong khi điền các thông tin chi tiết của project, sử dụng cùng package name mà bạn đã đăng ký lên firebase console. trường hợp của mình là com.phongnx.firebaserealtimedatabase.

4. Kết nối với Firebase

4.1. Dán tệp google-services.json vào project’s app folder. Bước này rất quan trọng vì dự án của bạn sẽ không xây dựng mà không có tệp tin này.

4.2. Bây giờ mở file build.gradle trong project’s home directory và thêm google playstore dependency.

    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
        classpath 'com.google.gms:google-services:3.0.0'
    }

4.3. Mở file app/build.gradle và thêm firebase database dependency. Ở cuối file, add apply plugin: ‘com.google.gms.google-services’

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'com.google.firebase:firebase-database:10.0.1'
    testCompile 'junit:junit:4.12'
}

apply plugin: 'com.google.gms.google-services'
5. SOURCE CODE

https://github.com/phongnx1/AndroidApp/tree/master/FirebaseRealtimeDatabase

6. Thiết lập Rule

7. Demo

Đây là app đơn giản demo tính năng realtime database của firebase, Các bạn có thể test thêm data trên app, muốn xóa data, các bạn thực hiện ở firebase console nhé :D. Để demo chức năng offline thì các bạn ngắt kết nối internet, thực hiện add artist, sau đó bật kết nối internet và confirm data đã được đồng bộ trên firebase console hoặc các điện thoại có cài app này nhé.

V. Kết Luận

Với bài viết này, mình đã cung cấp cho các bạn cái nhìn tổng quát về Firebase realtime database, Cách khởi tạo một ứng dụng android kết nối với firebase. Thật nhanh chóng và dễ dàng khi Firebase cung cấp cho chúng ta các kết nối cũng như Realtime DB để phát triển ứng dụng.
Như bạn đã thấy, Firebase Realtime DB được tổ chức theo dạng cây – nhánh chứ không phải dạng hàng – cột và đây có thể là một vấn đề hết sức nan giải cho những lập trình viên đã và đang thiết kế cơ sở dữ liệu dạng bảng. Thực ra không hẳn là một hạn chế, vì FRD được tạo ra dựa trên ý tưởng này ngay từ đầu. Và họ cũng không có ý định cho ra mắt thêm một dạng cơ sở dữ liệu dạng bảng, ít nhất là cho tới thời điểm hiện tại.
Tuy nhiên, nếu bạn cần lắm sự kết nối giữa các hàng trong một bảng, chẳng hạn như việc quản lí tiền lương thì SQLD cũ kĩ vẫn sẽ tỏ ra vượt trội hơn, mặc dù bạn vẫn có khả năng xoay sở đối với FRD. Còn nếu bạn phải quản lí các dữ liệu theo kiểu liên bảng, tức là bạn phải thực hiện thao tác JOIN các dữ liệu trong SQLD, có thể việc thực hiện các thao tác thay thế trên FRD trên thực tế sẽ khó khăn hơn là bạn nghĩ.
Một vấn đề quan trọng hơn nữa, là PRIMARY KEY. Các bạn ít nhiều đã biết rồi, PRIMARY KEY là một trong những điều cần thiết để quản lí hiệu quả CSDL SQLD. Tuy nhiên trong FRD thì hoàn toàn không tồn tại khái niệm PRIMARY KEY, do đó bạn sẽ cần cẩn thận trong việc quản lí các objects để tránh bị cập nhật sai các dữ liệu đã có sẵn.
Tóm lại, Firebase Realtime Database ngoài ưu điểm mang tính realtime thì còn có tính linh hoạt rất cao, dễ dàng trong việc bổ sung hoặc cắt bớt các trường trong một Object. Tuy nhiên, sự liên hệ tương ứng giữa các đối tượng trong Firebase Realtime DB sẽ là một bài toán không hề dễ và cách xử lí phụ thuộc rất nhiều vào trình độ và kinh nghiệm của lập trình viên, cũng như bản chất và mục đích của bản thân CSDL được tạo.

VI. Tài liệu tham khảo

  1. https://www.androidhive.info/2016/10/android-working-with-firebase-realtime-database/
  2. https://firebase.google.com/docs/database/
  3. https://viblo.asia/p/lam-viec-voi-firebase-realtime-database