Giap Hiep

I'm Giap Hiep

I'm a web developer, a gymer. I enjoy share something i know that help people's work!
Giap Hiep

Cơ bản về Firebase trong Android

Cơ sở dữ liệu là một phần quan trọng của rất nhiều dự án. Chúng ta lưu trữ, truy xuất, xóa và cập nhật dữ liệu trong cơ sở dữ liệu được lấy từ ứng dụng hoặc từ phần mềm mà chúng tạo ra. Mọi thứ trở nên khó khăn hơn khi bạn muốn cập nhật và lưu tất cả dữ liệu theo thời gian thực. Đừng lo, mọi thứ trở nên dễ dàng hơn khi bạn sử dụng Firebase. Nó sẽ giúp chúng ta cập nhật dữ liệu theo thời gian thực một cách dễ dàng.
Trong blog này, chúng ta sẽ tìm hiểu về những ưu điểm và cách sử dụng Firebase.

Firebase Realtime Database là gì?

Nói một cách đơn giản, Firebase Realtime Database là một loại cơ sở dữ liệu được lưu trữ trên cloud, nó cho phép truy cập từ bất kỳ nền tảng nào như Android, iOS hay Web. Vì vậy, chúng ta chỉ cần tạo cơ sở dữ liệu một lần và sử dụng nó trên các nền tảng khác nhau. Dữ liệu được lưu trữ trong cơ sở dữ liệu có dạng NoQuery và được lưu trữ ở định dạng JSON.
Điều tuyệt với nhất là bất cứ khi nào có sự thay đổi trong cơ sở dữ liệu, nó sẽ được cập nhật ngay lập tức đến tất cả các thiết bị được kết nối với nó.

Ưu điểm của Firebase Realtime Database.

  • Cập nhật dữ liệu thời gian thực: Dữ liệu được lưu trữ trong Firebase Realtime Database sẽ được cập nhật trên các nền tảng kết nối theo thời gian thực.
  • Khả năng tiếp cận lớn: Firebase Realtime Database có thể được truy cập từ nhiều nền tảng khác nhau như Android, iOS, Web. Vì vậy, bạn không cần phải viết code riêng cho các nền tảng khác nhau.
  • Chế độ ngoại tuyến: Đây là điểm được đánh giá rất cao của Firebase Realtime Database. Nếu bạn thay đổi dữ liệu trong ứng dụng khi không kết nối internet thì Firebase sẽ cập nhật lại dữ liệu ngay khi bạn kết nối với internet.
  • Không cần sử dụng server: Chúng ta không cần một server để lưu trữ dữ liệu.
  • Kiểm soát truy cập dữ liệu: Bạn có thể kiểm soát quyền truy cập dữ liệu của người dùng.

Dữ liệu sẽ được lưu trữ dưới dạng JSON

Dữ liệu được lưu trữ trong Firebase theo định dạng JSON, tức là toàn bộ cơ sở dữ liệu sẽ là một JSON tree có nhiều node. Không giống như SQL, chúng ta không có bảng hoặc bản ghi trong JSON tree.
Bất cứ khi nào bạn thêm dữ liệu vào JSON tree, nó sẽ trở thành một node trong cấu trúc JSON hiện có với một số khóa được liên kết với nó. Vì vậy, tất cả dữ liệu trên Firebase được lưu trữ dưới dạng JSON object. Ví dụ:

{
    "company": {
        "name": "MindOrks",
        "address": "Gurugram"
    }
}

Quy tắc cấu hình cơ sở dữ liệu

Dữ liệu hiện tại trong cơ sở dữ liệu rất quan trọng và bạn không nên cấp quyền truy cập cho mọi người vào cơ sở dữ liệu của bạn. Để làm như vậy, Firebase có một số quy tắc cấu hình cơ sở dữ liệu có thể được sử dụng để cung cấp quyền truy cập khác nhau cho những người dùng khác nhau. Sau đây là các quy tắc cấu hình cơ sở dữ liệu:

  • Default: Quyền truy cập đọc và ghi vào cơ sở dữ liệu của bạn bị vô hiệu hóa và không ai có thể đọc hoặc ghi dữ liệu từ cơ sở dữ liệu ở chế độ này. Bạn chỉ có thể truy cập vào cơ sở dữ liệu từ Firebase Console.
// These rules don't allow anyone read or write access to your database
{
  "rules": {
    ".read": false,
    ".write": false
  }
}
  • Public: Bất cứ ai cũng có thể thay đổi dữ liệu trong cơ sở dữ liệu. Quy tắc này thường được sử dụng khi bạn đang kiểm tra ứng dụng của mình và sau khi kiểm tra ứng dụng, bạn chỉ có thể đặt quy tắc thành User
// These rules give anyone, even people who are not users of your app,
// read and write access to your database
{
  "rules": {
    ".read": true,
    ".write": true
  }
}
  • User: Người dùng ứng dụng của bạn có thể đọc và ghi vào cơ sở dữ liệu. Bạn có thể xác thực người dùng bằng Firebase Login and Authentication và sau đó, người dùng của bạn sẽ có quyền truy cập vào cơ sở dữ liệu.
// These rules grant access to a node matching the authenticated
// user's ID from the Firebase auth token
{
  "rules": {
    "users": {
      "$uid": {
        ".read": "$uid === auth.uid",
        ".write": "$uid === auth.uid"
      }
    }
  }
}

Ví dụ

Trong ví dụ này, chúng ta sẽ lưu trữ tên và số điện thoại vào cơ sở dữ liệu và đồng thời, chúng ta sẽ hiển thị tên và số điện thoại di động của người dùng theo thời gian thực. Vậy bắt đầu nhé!

Bước 1: Tạo một project mới hoặc mở một project có sẵn.

Bước 2: Trong Android Studio, đăng nhập bằng email của bạn. Bạn có thể tìm thấy nút đăng nhập ở góc trên cùng bên phải của Android Studio. (Hãy nhớ id email mà bạn đã sử dụng ở đây)

Bước 3: Vào trang chủ của Firebase và đăng nhập. (sử dụng cùng một id email như được sử dụng trong Android Studio để đăng nhập nhé!)

Bước 4: Sau khi đăng nhập thành công, click vào nút "Go To Console" ở phía trên bên phải của trang web.

Bước 5: Click nút "Add Project".

Bước 6: Nhập các chi tiết cần thiết của project và bấm vào Continue.

Bước 7: Sau khi tạo xong project, bạn sẽ thấy hình ảnh bên dưới.

Tại đây, tất cả các dịch vụ của Firebase đều được hiển thị và bạn có thể sử dụng bất kỳ dịch vụ nào trong số đó.

Bước 8: Nhấp vào "Database" và sau đó trong phần Realtime Database, nhấp vào "Create Database".

Bước 9: Vì chúng ta chỉ sử dụng database cho mục đích làm ví dụ. Vì vậy, chọn tùy chọn "Start in test mode" và nhấp vào "Enable".

Bước 10: Bây giờ, hãy quay lại project trong Android Studio của bạn. Chúng ta sẽ kết nối dự án Firebase project trong Android Studio. Vì vậy, nhấp vào Tools > Firebase > Realtime Database > Save and retrieve data.

Bước 11: Sau đó bấm vào "Connect to Firebase". Một danh sách các project sẽ được hiển thị lên. Chọnproject mà bạn đã tạo trên trang web Firebase và nhấp vào "Connect to Firebase".

Bước 12: Cuối cùng, bạn phải thêm dependency của Firebase Realtime Database trong project bằng cách nhấp vào nút "Add Firebase Realtime Database to your app" và sau đó chọn "Accept changes".

Tạo giao diện cho main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".UserAccount">

    <TextView
        android:id="@+id/user_name"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:text="@string/dummy_name"
        android:textSize="32sp"/>

    <TextView
        android:id="@+id/user_mobile"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/user_name"
        android:text="@string/dummy_mobile"
        android:textSize="32sp"/>

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/textInputLayout"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:layout_marginTop="32dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/user_mobile">

        <EditText
            android:id="@+id/name_edt_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:hint="@string/name_hint" />

    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/textInputLayout2"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textInputLayout">

        <EditText
            android:id="@+id/mobile_edt_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:hint="@string/mobile_hint"
            android:inputType="phone" />

    </com.google.android.material.textfield.TextInputLayout>

    <Button
        android:id="@+id/update_user_btn"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:layout_marginTop="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textInputLayout2"
        android:text="@string/update_user_info"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Tạo class UserInfo

Chúng ta đã hoàn thành phần UI trong project này. Tạo class UserInfo.kt để lưu trữ dữ liệu

package com.mindorks.firebaseloginsignup

import com.google.firebase.database.IgnoreExtraProperties

@IgnoreExtraProperties
data class UserInfo(
    var name: String? = "",
    var mobile: String? = ""
)

Get Database Reference

Để đọc và ghi dữ liệu, bạn cần phải lấy ra một instance của DatabaseReference. Chúng ta sử dụng phương thức getReference () và truyền reference node cho nó.

private lateinit var dbReference: DatabaseReference
//some code

//get reference to the "users" node
dbReference = FirebaseDatabase.getReference("users")

Phương thức setValue (), sẽ xét lại giá trị mới cho dữ liệu. Ở đây, userId là id của người dùng hiện tại đang viết trên cơ sở dữ liệu.

dbReference.child("users").child(userId).setValue(user)

Chúng ta cũng có thể cập nhật dữ liệu thuộc tính của đối tượng User như sau:

dbReference.child("users").child(userId).child("name").setValue(name)

Chúng ta đang sử dụng Realtime Database. Vì vậy, chúng ta phải lắng nghe những thay đổi được thực hiện cho cơ sở dữ liệu của chúng tôi. Để lắng nghe những thay đổi trong cơ sở dữ liệu, chúng ta có thể sử dụng phương thức addValueEventListener () để thêm ValueEventListener vào DatabaseReference. Code sẽ như sau:

private fun addUserChangeListener() {
        // User data change listener
        dbReference.child(userId).addValueEventListener(object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {
                val user = dataSnapshot.getValue(UserInfo::class.java)

                // Check for null
                if (user == null) {
                  return
                }


                // Display newly updated name and email
                userNameTv.setText(user?.name).toString()
                userMobileTv.setText(user?.mobile).toString()

                // clear edit text
                userNameEt.setText("")
                userMobileEt.setText("")
            }

            override fun onCancelled(error: DatabaseError) {
                // Failed to read value
            }
        })
    }

onDataChange () sẽ được gọi khi có sự thay đổi dữ liệu của cơ sở dữ liệu và nếu vì một số lý do nào đó, ứng dụng không thể đọc dữ liệu từ cơ sở dữ liệu, thì phương thức onCancelled () sẽ được gọi.

Xóa dữ liệu

Để xóa dữ liệu khỏi một vị trí cụ thể, bạn có thể sử dụng phương thức removeValue () trên tham chiếu đến vị trí của dữ liệu đó.