Phát triển ứng dụng cơ sở dữ liệu thời gian thực với Firebase-phần 3

Bài 1 các bạn đã biết cách kết nối và truy vấn Realtime Database Firebase, Bài 2 biết cách thêm mới dữ liệu vào Firbase. Trong bài này Tui sẽ hướng dẫn các bạn cách chỉnh sửa và xóa dữ liệu khỏi Realtime Database Firebase.

Tiếp tục mở lại Project ở bài 2, Ta bổ sung thêm 3 chức năng: Lấy chi tiết Cập nhật và xóa.

Ta tạo một màn hình mới tên là CapNhatContactActivity, bằng cách bấm chuột phải vào package/ chọn New / Chọn Activity/ chọn Empty Activity:

Sau khi chọn Empty Activity, ta nhập tên CapNhatContactActivity:

sau khi nhập xong, nhấn FINISH để tạo màn hình Cập nhật, thiết kế giao diện màn hình này như hình dưới đây:

Mục đích của màn hình này là:

– Truy vấn chi tiết 1 Contact trên Firebase dựa vào Contact ID được chọn trên ListView ở màn hình chính

– Cho phép Cập nhật

– Cho phép Xóa

XML Layout của màn hình này như sau:

[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".CapNhatContactActivity">
<TextView
android:id="@+id/textView0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Contact Id:"
android:textSize="25sp" />
<EditText
android:id="@+id/edtContactId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Contact Id ở đây"
android:inputType="textPersonName"
android:textSize="25sp" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Ten:"
android:textSize="25sp" />
<EditText
android:id="@+id/edtTen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Tên ở đây"
android:inputType="textPersonName"
android:textSize="25sp" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Email:"
android:textSize="25sp" />
<EditText
android:id="@+id/edtEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Email ở đây"
android:inputType="textEmailAddress"
android:textSize="25sp" />
<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Phone:"
android:textSize="25sp" />
<EditText
android:id="@+id/edtPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Phone ở đây"
android:inputType="phone"
android:textSize="25sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">

<Button
android:id="@+id/btnChinhSua"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cập Nhật"
android:textSize="25sp" />
<Button
android:id="@+id/btnXoa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Xóa"
android:textSize="25sp" />
</LinearLayout>
</LinearLayout>
[/code]

Tiến hành bổ sung sự kiện cho ListView ở màn hình MainActivity:

[code language=”java”]
lvContact.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String data=adapter.getItem(position);
String key=data.split("\n")[0];
Intent intent=new Intent(MainActivity.this,CapNhatContactActivity.class);
intent.putExtra("KEY",key);
startActivity(intent);
}
});
[/code]

Vì ở màn hình chính Tui hiển thị mỗi dòng là các thông số Contact Id, Phone, Email, Name được nối nhau bằng ký tự xuống dòng \n. Nên ở đây khi có được dòng đang chọn, Tui dùng hàm split để tách ra, phần tử đầu tiên là Contact ID nên lấy index là [0]

Contact ID này sẽ được gửi qua màn hình CapNhatContactActivity, Tui đặt tên nó là KEY. Bên màn hình Cập nhật sẽ dựa vào KEY này để lấy thông tin chi tiết từ Firebase cũng như dùng cho cập nhật, xóa (Các bạn đừng thắc mắc là tại sao không truyền hết qua luôn để không phải mất công truy suất lại). Ở đây Tui có 2 lý do:

  • Lý do 1: Tui muốn hướng dẫn các bạn cách lấy thông tin chi tiết từ Firebase khi có Key
  • Lý do 2: Trong thực tế dữ liệu có rất nhiều thuộc tính, trong màn hình danh sách không phải tải hết về, mà chỉ tải một số thông tin quan trọng, do đó trong màn hình chí tiết ta mới tải hết về dựa vào Key

OK, giờ quay lại màn hình CapNhatContactActivity, coding để lấy chi tiết Contact:

[code language=”java”]
package com.communityuni.realtimedatabasefirebase;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.HashMap;

public class CapNhatContactActivity extends AppCompatActivity {
EditText edtId,edtTen,edtPhone,edtEmail;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cap_nhat_contact);
addControls();
getContactDetail();
}

private void getContactDetail() {
Intent intent=getIntent();
final String key=intent.getStringExtra("KEY");
FirebaseDatabase database = FirebaseDatabase.getInstance();
//Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
DatabaseReference myRef = database.getReference("contacts");

//truy suất và lắng nghe sự thay đổi dữ liệu
//chỉ truy suất node được chọn trên ListView myRef.child(key)
//addListenerForSingleValueEvent để lấy dữ liệu đơn
myRef.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
try {
//nó trả về 1 DataSnapShot, mà giá trị đơn nên gọi getValue trả về 1 HashMap
HashMap<String,Object> hashMap= (HashMap<String, Object>) dataSnapshot.getValue();
//HashMap này sẽ có kích thước bằng số Node con bên trong node truy vấn
//mỗi phần tử có key là name được định nghĩa trong cấu trúc Json của Firebase
edtId.setText(key);
edtTen.setText(hashMap.get("name").toString());
edtEmail.setText(hashMap.get("email").toString());
edtPhone.setText(hashMap.get("phone").toString());
}
catch (Exception ex)
{
Log.e("LOI_JSON",ex.toString());
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w("LOI_CHITIET", "loadPost:onCancelled", databaseError.toException());
}
});
}

private void addControls() {
edtId=findViewById(R.id.edtContactId);
edtTen=findViewById(R.id.edtTen);
edtPhone=findViewById(R.id.edtPhone);
edtEmail=findViewById(R.id.edtEmail);
}
}
[/code]

Lưu ý trong sự kiện lấy chi tiết, Tui dùng addListenerForSingleValueEvent, nó khác với lấy danh sách Contact trong MainActivity nha (addValueEventListener).

Chạy lên ta có kết quả:

Khi chọn 1 Contact, ví dụ như Putin–> nó sẽ mò lên Realtime Database Firebase để lấy chi tiết  và trả về cho màn hình CapNhatContactActivity.

Tiếp tục bổ sung 2 sự kiện (dùng onClick XML) Cập nhật và Xóa cho màn hình Cập Nhật:

[code language=”xml”]
<Button
android:id="@+id/btnChinhSua"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="xuLySua"
android:text="Cập Nhật"
android:textSize="25sp" />
<Button
android:id="@+id/btnXoa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="xuLyXoa"
android:text="Xóa"
android:textSize="25sp" />
[/code]

Coding cho 2 sự kiện này trong màn hình CapNhatContactActivity như sau:

Sự kiện sửa:

[code language=”java”]
public void xuLySua(View view) {
String key=edtId.getText().toString();
String phone=edtPhone.getText().toString();
String name=edtTen.getText().toString();
String email=edtEmail.getText().toString();
FirebaseDatabase database = FirebaseDatabase.getInstance();
//Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
DatabaseReference myRef = database.getReference("contacts");
myRef.child(key).child("phone").setValue(phone);
myRef.child(key).child("email").setValue(email);
myRef.child(key).child("name").setValue(name);
finish();
}
[/code]

Ở trên biến key là ContactId, ta sửa giá trị các node bên trong của nó lần lượt có: Phone, email, name:

myRef.child(key).child(“phone”) -> truy suất tới node phone

myRef.child(key).child(“phone”).setValue(phone)–> đổi mới giá trị cho node phone.

Sự kiện Xóa:

[code language=”java”]
public void xuLyXoa(View view) {
String key=edtId.getText().toString();
FirebaseDatabase database = FirebaseDatabase.getInstance();
//Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
DatabaseReference myRef = database.getReference("contacts");
myRef.child(key).removeValue();
finish();
}
[/code]

Ta dùng hàm removeValue() để xóa, hoặc setValue(null) nha. Còn muốn cập nhập/ xóa nhiều thì dùng hàm updateChildren, truyền vào là 1 HashMap.

Cuối cùng ta có coding đầy đủ của màn hình CapNhatContactActivity như sau:

[code language=”java”]
package com.communityuni.realtimedatabasefirebase;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.HashMap;

public class CapNhatContactActivity extends AppCompatActivity {
EditText edtId,edtTen,edtPhone,edtEmail;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cap_nhat_contact);
addControls();
getContactDetail();
}

private void getContactDetail() {
Intent intent=getIntent();
final String key=intent.getStringExtra("KEY");
FirebaseDatabase database = FirebaseDatabase.getInstance();
//Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
DatabaseReference myRef = database.getReference("contacts");

//truy suất và lắng nghe sự thay đổi dữ liệu
//chỉ truy suất node được chọn trên ListView myRef.child(key)
//addListenerForSingleValueEvent để lấy dữ liệu đơn
myRef.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
try {
//nó trả về 1 DataSnapShot, mà giá trị đơn nên gọi getValue trả về 1 HashMap
HashMap<String,Object> hashMap= (HashMap<String, Object>) dataSnapshot.getValue();
//HashMap này sẽ có kích thước bằng số Node con bên trong node truy vấn
//mỗi phần tử có key là name được định nghĩa trong cấu trúc Json của Firebase
edtId.setText(key);
edtTen.setText(hashMap.get("name").toString());
edtEmail.setText(hashMap.get("email").toString());
edtPhone.setText(hashMap.get("phone").toString());
}
catch (Exception ex)
{
Log.e("LOI_JSON",ex.toString());
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w("LOI_CHITIET", "loadPost:onCancelled", databaseError.toException());
}
});
}

private void addControls() {
edtId=findViewById(R.id.edtContactId);
edtTen=findViewById(R.id.edtTen);
edtPhone=findViewById(R.id.edtPhone);
edtEmail=findViewById(R.id.edtEmail);
}

public void xuLySua(View view) {
String key=edtId.getText().toString();
String phone=edtPhone.getText().toString();
String name=edtTen.getText().toString();
String email=edtEmail.getText().toString();
FirebaseDatabase database = FirebaseDatabase.getInstance();
//Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
DatabaseReference myRef = database.getReference("contacts");
myRef.child(key).child("phone").setValue(phone);
myRef.child(key).child("email").setValue(email);
myRef.child(key).child("name").setValue(name);
finish();
}
public void xuLyXoa(View view) {
String key=edtId.getText().toString();
FirebaseDatabase database = FirebaseDatabase.getInstance();
//Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
DatabaseReference myRef = database.getReference("contacts");
myRef.child(key).removeValue();
finish();
}
}
[/code]

Chạy phần mềm lên, giả sử chọn Contact có tên là Tám:

Ta bấm cập nhật, dữ liệu sẽ được update luôn trên Firebase Server, và bất kỳ client nào đang sài phần mềm này cũng thấy sự thay đổi đó.

Giả sử bạn nhấn nút Xóa, trên Firebase sẽ đánh dấu mà đỏ báo cho ta chuẩn bị xóa-> và xóa thành công:

Như vậy Tui đã hướng dẫn xong cách: lấy chi tiết, cập nhật và xóa, các bạn thực hành lại nha.

Đây là source code của phần này: Tải code ở đây

Bài sau Tui sẽ hướng dẫn phần nâng cao: dùng java model class, cũng như lắng nghe kết quả thực hiện, transaction… các bạn chú ý theo dõi.

Chúc các bạn thành công!

2 thoughts on “Phát triển ứng dụng cơ sở dữ liệu thời gian thực với Firebase-phần 3”

Leave a Reply