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

Trong các bài hướng dẫn trước (Xem tại đây) Tui đã trình bày hoàn chỉnh thác tác CRUD trên Realtime Database Firebase, với những ví dụ từ cơ bản đến nâng cao, nó đã giúp các bạn hiểu và tự tạo được những ứng dụng riêng để Android có thể tương tác với Realtime Database Firebase.

Ở bài này, Tui muốn hướng dẫn thêm một vài trường hợp đặc biệt đó là: Làm thể nào để Chụp hình cũng như lấy hình từ SD Card rồi đưa hình này lên Realtime Database Firebase.

Trong hệ sinh thái Firebase của Google thì họ hỗ trợ rất nhiều công cụ, trong đó có Cloud Storage For Firebase giúp bạn có thể upload/download 1 file bất kỳ lên Cloud của Google. Phần Cloud Storage Tui sẽ có những TUT hướng dẫn riêng. Còn trong bài này Tui vẫn dùng dự án từ bài số 4, tiếp tục hiệu chỉnh phần mềm để thêm các chức năng: CHỤP HÌNH + CHỌN HÌNH từ SD Card + Đưa hình lên Realtime Database Firebase + Tải hình từ Realtime Database Firebase.

Bạn nhớ mở lại Project ở phần 4 nha.

Sau đó tiến hành làm các thao tác như Tui hướng dẫn dưới này:

Tạo một màn hình mới, tên là ThemContactActivity: Bấm chuột phải vào package/ chọn new / Chọn Activit / chọn Empty Activity:

Sau đó đặt tên: ThemContactActivity

Đặt tên xong nhấn Finish để tạo màn hình, thiết kế màn hình Thêm Contact như dưới đây:

Ở trên ta có thêm 2 ImageButton: Chụp ảnh + chọn Ảnh từ SD Card

Và thêm Image View để hiển thị hình ảnh mới chụp hoặc hình ảnh lấy từ SD Card

Đây là XML layout của màn hình Thêm Contact:

[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=".ThemContactActivity">
<TextView
android:id="@+id/textView0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Contact Id:"
android:textSize="15sp" />

<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="15sp" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Ten:"
android:textSize="15sp" />

<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="15sp" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Email:"
android:textSize="15sp" />

<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="15sp" />
<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Phone:"
android:textSize="15sp" />

<EditText
android:id="@+id/edtPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Phone ở đây"
android:inputType="phone"
android:textSize="15sp" />
<TextView
android:id="@+id/textView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Chọn Hình:"
android:textSize="15sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >

<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnCapture"
android:src="@drawable/camera" />

<ImageButton
android:id="@+id/btnChoose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:src="@drawable/choose" />
</LinearLayout>

<ImageView
android:id="@+id/imgPicture"
android:layout_width="match_parent"
android:layout_height="150dp"
app:srcCompat="@drawable/noimage" />
<Button
android:onClick="xuLyThemMoi"
android:id="@+id/btnDongYThem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Đồng Ý Thêm"
android:textSize="15sp" />
</LinearLayout>

[/code]

Chỉnh sửa coding cho ThemContactActivity để có thể đẩy hình lên Realtime Database Firebase:

[code language=”java”]

package com.communityuni.advancedrealtimedatabasefirebase;

import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Base64;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;

import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class ThemContactActivity extends AppCompatActivity {
ImageButton btnCapture;
ImageButton btnChoose;
ImageView imgPicture;
Bitmap selectedBitmap;
EditText edtId,edtTen,edtPhone,edtEmail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_them_contact);
addControls();
addEvents();
}
public void addControls()
{
btnCapture = findViewById(R.id.btnCapture);
btnChoose= findViewById(R.id.btnChoose);
imgPicture=findViewById(R.id.imgPicture);
edtId=findViewById(R.id.edtContactId);
edtTen=findViewById(R.id.edtTen);
edtPhone=findViewById(R.id.edtPhone);
edtEmail=findViewById(R.id.edtEmail);
}
public void addEvents() {
btnCapture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
capturePicture();
}
});
btnChoose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
choosePicture();
}
});
}
//xử lý chọn hình
private void choosePicture() {
Intent pickPhoto = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhoto , 200);//one can be replaced with any action code
}
//xử lý chụp hình
private void capturePicture() {
Intent cInt = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cInt,100);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 100&& resultCode == RESULT_OK) {
//xử lý lấy ảnh trực tiếp lúc chụp hình:
selectedBitmap = (Bitmap) data.getExtras().get("data");
imgPicture.setImageBitmap(selectedBitmap);
}
else if(requestCode == 200&& resultCode == RESULT_OK) {
try {
//xử lý lấy ảnh chọn từ điện thoại:
Uri imageUri = data.getData();
selectedBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
imgPicture.setImageBitmap(selectedBitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void xuLyThemMoi(View view) {
try {
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");
String contactId=edtId.getText().toString();
String ten = edtTen.getText().toString();
String phone = edtPhone.getText().toString();
String email = edtEmail.getText().toString();
myRef.child(contactId).child("phone").setValue(phone);
myRef.child(contactId).child("email").setValue(email);
myRef.child(contactId).child("name").setValue(ten);

//đưa bitmap về base64string:
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
selectedBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream .toByteArray();
String imgeEncoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
myRef.child(contactId).child("picture").setValue(imgeEncoded);

finish();
}
catch (Exception ex)
{
Toast.makeText(this,"Error:"+ex.toString(),Toast.LENGTH_LONG).show();
}
}
}

[/code]

Coding ở trên có 3 điểm mới:

Thứ nhất: Chụp hình

Thứ 2: Chọn hình từ thiết bị

Thứ 3: Đưa hình về Base64String

Lưu ý rằng ta phải cấp quyền truy suất CAMERA, cũng như Storage cho phần mềm nhé, chỉnh sửa lại AndroidManifest:

[code language=”xml”]

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.communityuni.advancedrealtimedatabasefirebase">

<uses-feature
android:name="android.hardware.Camera"
android:required="true"></uses-feature>

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

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ThemContactActivity" />
</application>

</manifest>

[/code]

Sau đó bổ sung Option Menu ở màn hình MainActivity để thêm menu “Thêm Contact” cho người dùng sử dụng, bước thêm Menu xem lại phần 2:

Bổ sung coding hiển thị menu và xử lý chọn menu cho MainActivity:

[code language=”java”]

@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater=getMenuInflater();
menuInflater.inflate(R.menu.main_menu,menu);
return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId()==R.id.mnuAdd)
{
//mở màn hình thêm ở đây
Intent intent=new Intent(MainActivity.this,ThemContactActivity.class);
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}

[/code]

Chạy phần mềm lên ta có:

Xem màn hình thêm Contact có các chức năng: Chụp hình, chọn hình, đưa hình lên Realtime Database Firebase:

Lưu ý từ bản Android version 6.0 trở về đây do tính bảo mật nên những phần mềm không trực tiếp chạy từ Google Play, ngoài bước cấp quyền trong Android Manifest ra, ta còn phải cấp quyền trong thiết bị nữa mới được, nếu quên không cấp quyền thêm 1 lần nữa trong thiết bị thì ứng dụng sẽ không thể chạy được.

Ta cấp theo theo bước sau:

Quay trở lại màn hình HOME SCREEN của điện thoại, chọn phần mềm mà ta đang lập trình này-> nhấn thật lâu vào nó rồi chọn  “App Infor”:

Chọn App Infor xong ta có giao diện:

Ở trên ta thấy mục “Permissions” đang báo là chưa có quyền nào được cấp, ta nhấn vào nó:

Ta tick enable nó lên như hình ở trên-> đã thành công, giờ có thể sử dụng được phần mềm rồi nha:

Lưu ý ở trên 2 ImageButton: Chụp hình + Chọn hình tùy ta chọn nha: Muốn chụp hình Live thì bấm vào nút đầu tiên, muốn chọn 1 hình có sẵn trong máy thì chọn nút 2.

Sau khi nhập đầy đủ thông tin và hình ảnh thì bấm nút “Đồng ý thêm”, chương trình thêm thành công và quay trở về màn hình chính, lúc này ta có kết quả:

Trên Realtime Database Firebase ta có hình ảnh dưới dạng Base64String, và giao diện cũng có Contact mới này.

Như vậy là tới đây Tui đã hướng dẫn xong bước thêm 1 Contact có hình ảnh.

Bây giờ ta bổ sung chức năng cập nhập Contact. Vì trước đó ta có các Contact mà chưa có hình ảnh (tức là không có thuộc tính picture). giờ ta thêm chức năng này để cập nhật hình cho bất kỳ contact nào.

Ta tạo màn hình tên “CapNhatContactActivity”, bước làm tương tự như ThemContactActivity. ta chỉnh giao diện màn hình cập nhật như dưới đây:

Đây là XML layout của màn hình Cập nhật:

[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="15sp" />

<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="15sp" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Ten:"
android:textSize="15sp" />

<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="15sp" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Email:"
android:textSize="15sp" />

<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="15sp" />
<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Phone:"
android:textSize="15sp" />

<EditText
android:id="@+id/edtPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Phone ở đây"
android:inputType="phone"
android:textSize="15sp" />
<TextView
android:id="@+id/textView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Chọn Hình:"
android:textSize="15sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >

<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnCapture"
android:src="@drawable/camera" />

<ImageButton
android:id="@+id/btnChoose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:src="@drawable/choose" />
</LinearLayout>

<ImageView
android:id="@+id/imgPicture"
android:layout_width="match_parent"
android:layout_height="150dp"
app:srcCompat="@drawable/noimage" />
<Button
android:onClick="xuLyCapNhat"
android:id="@+id/btnDongCapNhat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Đồng Ý Cập Nhật"
android:textSize="15sp" />
</LinearLayout>

[/code]

Nhiệm vụ của màn hình Cập nhật là:

  • hiển thị chi tiết Contact được chọn trên giao diện ListView, bao gồm hình ảnh  Base64String được tải về từ Realtime database firebase
  • cho phép cập nhật dữ liệu cho Contact bao gồm cả hình ảnh

Chỉnh sửa coding của MainActivity: Nhấn vào 1 Contact nào trên Listview thì mở màn hình Cập nhật ra:

[code language=”java”]

lvContact.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Contact data=adapter.getItem(position);
Intent intent=new Intent(MainActivity.this,CapNhatContactActivity.class);
intent.putExtra("KEY",data.getContactId());
startActivity(intent);
}
});

[/code]

Tiếp tục chỉnh sửa coding của màn hình CapNhatContactActivity:

[code language=”java”]

package com.communityuni.advancedrealtimedatabasefirebase;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;

import com.communityuni.model.Contact;
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.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;

public class CapNhatContactActivity extends AppCompatActivity {

EditText edtId,edtTen,edtPhone,edtEmail;
ImageView imgPicture;
ImageButton btnCapture;
ImageButton btnChoose;
Bitmap selectedBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cap_nhat_contact);
addControls();
getContactDetail();
addEvents();
}

private void getContactDetail() {
Intent intent=getIntent();
final String key=intent.getStringExtra("KEY");
final 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 {
Contact contact=dataSnapshot.getValue(Contact.class);
contact.setContactId(dataSnapshot.getKey());
edtId.setText(contact.getContactId());
edtTen.setText(contact.getName());
edtEmail.setText(contact.getEmail());
edtPhone.setText(contact.getPhone());
if(contact.getPicture()!=null) {
byte[] decodedString = Base64.decode(contact.getPicture(), Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
imgPicture.setImageBitmap(decodedByte);
}
}
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() {
btnCapture = (ImageButton) findViewById(R.id.btnCapture);
btnChoose= (ImageButton) findViewById(R.id.btnChoose);
imgPicture= (ImageView) findViewById(R.id.imgPicture);
edtId=findViewById(R.id.edtContactId);
edtTen=findViewById(R.id.edtTen);
edtPhone=findViewById(R.id.edtPhone);
edtEmail=findViewById(R.id.edtEmail);
}
public void addEvents() {
btnCapture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
capturePicture();
}
});
btnChoose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
choosePicture();
}
});
}
private void choosePicture() {
Intent pickPhoto = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhoto , 200);//one can be replaced with any action code
}

private void capturePicture() {
Intent cInt = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cInt,100);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 100&& resultCode == RESULT_OK) {
//xử lý lấy ảnh trực tiếp lúc chụp hình:
selectedBitmap = (Bitmap) data.getExtras().get("data");
imgPicture.setImageBitmap(selectedBitmap);
}
else if(requestCode == 200&& resultCode == RESULT_OK) {
try {
//xử lý lấy ảnh chọn từ điện thoại:
Uri imageUri = data.getData();
selectedBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
imgPicture.setImageBitmap(selectedBitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void xuLyCapNhat(View view) {
try {
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");
String contactId=edtId.getText().toString();
String ten = edtTen.getText().toString();
String phone = edtPhone.getText().toString();
String email = edtEmail.getText().toString();
myRef.child(contactId).child("phone").setValue(phone);
myRef.child(contactId).child("email").setValue(email);
myRef.child(contactId).child("name").setValue(ten);

//đưa bitmap về base64string:
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
selectedBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream .toByteArray();
String imgeEncoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
myRef.child(contactId).child("picture").setValue(imgeEncoded);

finish();
}
catch (Exception ex)
{
Toast.makeText(this,"Error:"+ex.toString(),Toast.LENGTH_LONG).show();
}
}
}

[/code]

Chạy phần mềm lên, ta chỉnh sửa dữ liệu cho contact7:

Khi cập nhật thành công, lúc này contact7 sẽ được bổ sung thêm thuộc tính picture và có giá trị là base64string cho bức hình gửi từ điện thoại lên.

Như vậy Tui đã hoàn chỉnh hướng dẫn toàn bộ chức năng CRUD nâng cao, bao gồm đưa hình ảnh lên Realtime Database Firebase và tải hình ảnh từ Realtime Database Firebase về điện thoại. Bài này khá phức tạp nhưng rất hay, Các bạn cố gắng hoàn thành nha.

Coding đầy đủ các bạn tải tại đây: Tải source code tại đây

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

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

Như vậy Tui đã hướng dẫn xong toàn bộ CRUD trong Realtime Database Firebase, các bạn nhớ làm theo thứ tự bài 1, bài 2, bài 3 nha.

Ở bài này Tui sẽ trình bày cách sử dụng Firebase ở mức cao hơn 1 xíu đó là: Sử dụng Java model class, Custom layout, tái sử dụng lại Realtime database ở bài trước(tức là giờ có 2 App cùng sử dụng 1 CSDL). Để giúp phần mềm được chuyên nghiệp và dễ dàng hơn cho Dev cũng như Customer.

Kết thúc bài này, ta có giao diện phần mềm như sau:

Các bước làm giống như các bài trước. Tuy nhiên trong bài này ta sẽ Bổ sung Customlayout, model class.

Tui mới update Android studio version mới nhất 3.2.1 (Tính tới ngày 15/10/2018) nên Tui new lại Project từ đầu nha.

Khởi động Android Studio:

Chọn Start a new Android Studio project:

Đặt tên Project là AdvancedRealtimeDatabaseFirebase rồi bấm Next

Chọn API 26 rồi bấm Next:

Tiếp tục chọn Empty Activity trong màn hình trên rồi bấm Next:

Mặc định để MainActivity rồi bấm Finish để tạo Project:

Đợi cho Project tạo xong ta sẽ kết nối tới Firebase bằng cách vào menu Tools/ chọn Firebase:

Sau khi chọn Firebase, lúc này công cụ trợ giúp sẽ xuất hiện:

Google cung cấp rất nhiều Service, nhưng ta cũng quan tâm tới Realtime Database-> nhấn vào mục có chữ này:

Tiếp tục nhấn vào “Save and retrieve data” để kết nối Realtime Database:

Google cũng  cung cấp nhiều bước, ta nhấn vào bước 1 “Connect to Firebase”, lúc này cửa sổ kết nối Firebase xuất hiện, tại bài Advanced này Tui muốn tái sử dụng lại CSDL ở các bài trước, Tui sẽ chọn mục số 2 “Choose an existing Firebase ỏ Google Project”:

Lúc này màn hình sẽ như sau:

rõ ràng ở trên bạn thấy “RealtimeDatabaseFirebase”, là Project ở các bài trước. Giờ ta bấm “Connect to Firebase”:

Ta chờ nó kết nối nha, nếu có lỗi xảy ra nó sẽ xuất hiện thông báo như màn hình dưới đây:

Đừng lo lắng, tiếp tục bấm lại “Connect to Firebase”, lúc này màn hình sau xuất hiện:

Ta nhấn vào “Sync” để đồng bộ, kết quả sẽ thành công như dưới đây:

Tiếp tục nhấn vào “Add the Realtime Database Rules” ở bước 2:

Chương trình sẽ yêu cầu thêm một số thư viện vào build.gradle. Ta nhấn Accept Changes:

Quan sát tập tin build.gradle, có lệnh: implementation ở cuối cùng. Ta xóa :15.0.0 đi:

Sau đó nhấn vào nút Try Again ở góc trên màn hình thông báo lỗi. Sau khi thành công thì ta bắt đầu lập trình được rồi. Lưu ý là khi kết nối thành công thì trên Firebase Console ta cũng thấy xuất hiện app này nha:

Như vậy bây giờ là 2 Ứng dụng Android có thể sử dụng chung 1 cơ sở dữ liệu Realtime Database Firebase rồi.

Ta xem lại cấu trúc JSON trên Firebase:

Bây giờ ta sẽ tạo 1 java class để mapping dữ liệu: Bằng cách nhấn chuột phải vào java/ chọn New / chọn Package:

Lúc này cửa sổ tạo package sẽ show ra như dưới đây:

Ta chọn dòng giữa rồi nhấn OK:

Đặt tên Package mới rồi nhấn OK. Lưu ý model để cuối cùng nha, sao cho nó có cấu trúc như vầy cho nó khóa học:

Tiếp tục nhấn chuột phải vào model / chọn New / chọn Java Class:

Màn hình tạo Lớp mới xuất hiện ra như bên dưới. Ta đặt tên lớp là Contact:

Nhấn OK để đồng ý tạo lớp Contact:

Chỉ sửa coding cho Lớp Contact này như dưới đây:

[code language=”java”]

package com.communityuni.model;

public class Contact {
private String contactId;
private String name;
private String phone;
private String email;

public String getContactId() {
return contactId;
}

public void setContactId(String contactId) {
this.contactId = contactId;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPhone() {
return phone;
}

public void setPhone(String phone) {
this.phone = phone;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}
}

[/code]

Vì ta làm Custom Layout để hiển thị danh sách Contact như hình:

Nên ta cần tạo 1 layout như sau:

Bấm chuột phải vào layout/ chọn New / chọn Layout resource file:

Đặt tên file là item rồi bấm OK:

Sau khi bấm OK, ta có giao diện:

Chỉnh sửa layout của item.xml sao cho giao diện đáp ứng yêu cầu:

Dưới đây là file XML layout của item.xml:

[code language=”xml”]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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:orientation="vertical">

<TextView
android:id="@+id/txtId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="@android:color/holo_red_dark"
android:textSize="25sp" />

<TextView
android:id="@+id/txtName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="?android:attr/colorActivatedHighlight"
android:textSize="25sp" />

<TextView
android:id="@+id/txtEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="@android:color/holo_green_dark"
android:textSize="25sp" />

<TextView
android:id="@+id/txtPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="@android:color/holo_blue_dark"
android:textSize="25sp" />

<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="?attr/colorControlActivated" />
</LinearLayout>

[/code]

Tiếp tục lặp lại bước tạo package mới, đó là package adapter:

Bấm chuột phải vào java/ chọn New/ chọn Package:

Chọn mục số 2:

Nhấn OK để đặt tên cho Package:

package adapter cũng đồng cấp với package model:

Tiếp tục tạo một lớp tên là : ContactAdapter để vẽ giao diện theo Custom Layout

Bấm chuột phải vào thư mục adapter/ chọn New/ chọn Java Class:

Đặt tên cho Class là ContactAdapter:

Sau đó nhấn OK để đồng ý tạo class, chỉnh sửa coding cho ContactAdapter như dưới đây:

[code language=”java”]

package com.communityuni.adapter;

import android.app.Activity;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.communityuni.advancedrealtimedatabasefirebase.R;
import com.communityuni.model.Contact;

public class ContactAdapter extends ArrayAdapter<Contact> {
Activity context;
int resource;
public ContactAdapter(Activity context, int resource) {
super(context, resource);
this.context=context;
this.resource=resource;
}

@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View custom=context.getLayoutInflater().inflate(resource,null);
TextView txtId=custom.findViewById(R.id.txtId);
TextView txtName=custom.findViewById(R.id.txtName);
TextView txtPhone=custom.findViewById(R.id.txtPhone);
TextView txtEmail=custom.findViewById(R.id.txtEmail);
Contact contact=getItem(position);
txtId.setText(contact.getContactId());
txtName.setText(contact.getName());
txtPhone.setText(contact.getPhone());
txtEmail.setText(contact.getEmail());
return custom;
}
}

[/code]

 

OK, cũng sắp xong rồi. Bây giờ bạn quay lại MainActivity để coding:

[code language=”java”]

package com.communityuni.advancedrealtimedatabasefirebase;

import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;

import com.communityuni.adapter.ContactAdapter;
import com.communityuni.model.Contact;
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;

public class MainActivity extends AppCompatActivity {

ListView lvContact;
ContactAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addControls();
getContactsFromFirebase();
}
private void getContactsFromFirebase() {
FirebaseDatabase firebaseDatabase=FirebaseDatabase.getInstance();
DatabaseReference myRef= firebaseDatabase.getReference("contacts");
adapter.clear();
myRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dss : dataSnapshot.getChildren())
{
//convert ra đối tượng Contact:
Contact contact=dss.getValue(Contact.class);
String key=dss.getKey();
contact.setContactId(key);
adapter.add(contact);
}
}

@Override
public void onCancelled(@NonNull DatabaseError databaseError) {

}
});
}

private void addControls() {
lvContact=findViewById(R.id.lvContact);
adapter=new ContactAdapter(this,R.layout.item);
lvContact.setAdapter(adapter);
}
}

[/code]

ở trên ta thấy dòng lệnh 37:

Contact contact=dss.getValue(Contact.class);

Dòng lệnh này để đưa dữ liệu trong HashMap về đúng kiểu Contact (nó tự mapping)

Khi có đối tượng contact rồi thì ta dán nó vào adapter là tự nhiên có giao diện như mong muốn

Chạy phần mềm lên ta sẽ có kết quả như sau:

Như vậy Tui đã hướng dẫn xong cách dùng model class, customlayout để truy suất dữ liệu từ Firebase. Cách làm cũng tương tự như loại cơ bản. tuy nhiên cách này sẽ khoa học hơn, tùy biến nhanh hơn.

Ngoài ra các thao tác Thêm, Sửa, Xóa. Các bạn có thể cho chương trình lắng nghe kết quả trả về, tương tự như:

Ví dụ: Thêm sự kiện xóa Contact khi nhấn lâu vào ListView và kiểm tra kết quả thành công hay thất bại:

[code language=”java”]

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addControls();
getContactsFromFirebase();
addEvents();
}
private void addEvents() {

lvContact.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Contact contact=adapter.getItem(position);
FirebaseDatabase firebaseDatabase=FirebaseDatabase.getInstance();
DatabaseReference myRef= firebaseDatabase.getReference("contacts");
myRef.child(contact.getContactId()).removeValue()
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Toast.makeText(MainActivity.this,"Thành công",Toast.LENGTH_LONG).show();

adapter.remove(contact);
}})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(MainActivity.this,"Lỗi rồi :"+ e.toString(),Toast.LENGTH_LONG).show();
}
});
return false;
}
});
}

[/code]

Xử lý cho Thêm Contact tương tự nha!

Đây là sourcode của chương trình: Tải ở đây

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

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!

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

phần 1 Tui đã hướng dẫn các bạn cách thức kết nối Android Studio tới Realtime Database Firebase,  cách thao tác Cơ sở dữ liệu trên console.firebase.google.com cũng như cách thức truy suất danh sách Contact từ Realtime Database Firebase xuống Client.

Ở bài này Tui sẽ hướng dẫn các bạn cách thức thêm mới dữ liệu từ Android lên Realtime Database. Tuy nhiên Tui vẫn sử dụng cách thức cơ bản nhất, khi nào qua hết tất cả các bài cơ bản, Tui sẽ trình bày phần nâng cao đó là sử dụng Model class, Transaction…. Còn những bài này chỉ cần các bạn hiểu cơ chế hoạt động, cách thức gọi lệnh là đủ rồi.

Tiếp tục mở lại Project đã được hướng dẫn trong phần 1.

Bổ sung Option Menu có 1 MenuItem là “Thêm Contact”  như hình dưới đây:

Để them Menu ta làm như sau:

Bấm chuột phải vào thư mục res/ chọn new/ chọn Directory:

Sau khi chọn Director, Android Studio sẽ cung cấp 1 màn hình yêu cầu ta đặt tên, Ta sẽ đặt tên Directory là: menu như hình trong màn hình dưới đây:

Đặt tên xong bấm OK, ta thấy thư mục menu được tạo vào Project:

Tiếp tục bấm chuột phải vào menu/ chọn New/ chọn menu resource file:

Android Studio sẽ cung cấp màn hình cho ta đặt tên menu cũng như các thông số cấu hình khác:

Để đơn giản, ta chỉ quan tâm tới phần File Name, đặt tên là : main_menu rồi bấm OK:

Ta tiến hành kéo Menu Item ra, đổi nhãn thành Thêm Contact, đặt id là mnuAdd.

đây là main_menu.xml:

[code language=”xml”]

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/mnuAdd"
android:title="Thêm Contact" />
</menu>

[/code]

Trong coding của màn hình MainActivity, Ta Override hàm onCreateOptionsMenu ra để tạo Menu cho Activity:

Chỉ cần gõ onCreate thì Android Studio cũng gợi ý ra hàm onCreateOptionsMenu, ta chỉ cần Enter là nó xổ hết ra cho lẹ:

Sau đó ta tiến hành cập nhật Coding như dưới đây:

[code language=”java”]

@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater=getMenuInflater();
menuInflater.inflate(R.menu.main_menu,menu);
return super.onCreateOptionsMenu(menu);
}

[/code]

Tiếp tục bổ sung hàm xử lý người dùng lựa chọn MenuItem – onOptionsItemSelected, ta cũng chi cần gõ 1 vài ký tự đầu onOption… nó tự xổ ra và ta chọn cho lẹ:

Ta sẽ có coding như sau:

[code language=”java”]

@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId()==R.id.mnuAdd) // kiểm tra người dùng chọn Menu Thêm Contact
{
//mở màn hình thêm ở đây (sẽ gọi sau)
}
return super.onOptionsItemSelected(item);
}

[/code]

Giờ Ta thêm một màn hình mới để nhập liệu cho Contact: Bấm chuột phải vào Package/ chọn New/ chọn Activity/ chọn Empty Activity :

Màn hình tạo Activity hiển thị ra, ta tiến hành đặt tên cho màn hình:

Ở trên ta đặt: là ThemContactActivity rồi bấm Finish
Tiến hành thiết kế giao diện cho màn hình Thêm mới:

XML Layout của activity_them_contact.xml 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=".ThemContactActivity">
<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" />

<Button
android:onClick="xuLyThemMoi"
android:id="@+id/btnDongYThem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Đồng Ý Thêm"
android:textSize="25sp" />

</LinearLayout>

[/code]

Để có thể lưu một dữ liệu mới từ Client lên Database Firebase thì không mấy khó khăn, do Google cung cấp cho ta phương thức đơn giản là: setValue(dữ_liệu). Nếu chưa tồn tại Name trên Firebase thì nó tự thêm mới, nếu Name đã tồn tại thì trở thành cập nhật. Một số loại dữ liệu mà Firebase hỗ trợ đó là:

  • String
  • Long
  • Double
    Boolean
  • Map<String, Object>
  • List<Object>

Object có thể là Java Object, ta đẩy luôn 1 đối tượng hoặc danh sách đối tượng lên Server Firebase được luôn nha (Sẽ trình bày chi tiết ở những bài sau).

Cái khó của phần này chắc chỉ là do ta mapping sai giữa cấu trúc JSON trên Realtime Database Firebase với các biến truyền vào trong Android mà thôi.

Chúng ta xem cái hình Tui chụp dưới này:

Hình trên là bộ 3: Giao diện tương tác – Coding – Reatime Database Firebase

Các bạn nhìn kỹ các mũi tên mà Tui  trỏ nha. Cấu trúc Cơ sở dữ liệu (JSON) trong Firebase như thế nào thì bạn phải truyền cho đúng nha.

Ở trên cấu trúc JSON ta có:

1 element contacts . Trong thẻ contacts  có rất nhiều element con contactX, Mỗi element con này lại có 3 Element con là: email, name, phone. Trong coding ta phải so khớp chính xác với các thành phần này nha. So Khớp chính xác thì tự nhiên dữ liệu sẽ được lưu thành công, và phía mobile client bất kỳ sẽ tự động cập nhật khi có dữ liệu thay đổi (Realtime)

Chi tiết Coding cho màn hình ThemContactActivity:

[code language=”java”]

package com.communityuni.realtimedatabasefirebase;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;

public class ThemContactActivity extends AppCompatActivity {
EditText edtId,edtTen,edtPhone,edtEmail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_them_contact);
addControls();
}
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 xuLyThemMoi(View view) {
try {
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");
String contactId=edtId.getText().toString();
String ten = edtTen.getText().toString();
String phone = edtPhone.getText().toString();
String email = edtEmail.getText().toString();
myRef.child(contactId).child("phone").setValue(phone);
myRef.child(contactId).child("email").setValue(email);
myRef.child(contactId).child("name").setValue(ten);
finish();
}
catch (Exception ex)
{
Toast.makeText(this,"Error:"+ex.toString(),Toast.LENGTH_LONG).show();
}
}
}

[/code]

Cuối cùng chỉnh sửa sự kiện nhấn MenuItem trong màn hình MainActivity:

[code language=”java”]

@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId()==R.id.mnuAdd)
{
//mở màn hình thêm ở đây
Intent intent=new Intent(MainActivity.this,ThemContactActivity.class);
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}

[/code]

Chạy lên Ta sẽ có kết quả như mong muốn: bất kỳ 1 Thiết bị nào thêm mới 1 Contact –> nó Sẽ được lưu trên RealTime Database Firebase –> Tất cả các thiết bị khác sẽ tự động cập nhật mới khi có dữ liệu thay đổi.

Đây là Coding đầy đủ của phần này: Link tải tại đây

Phần sau Tui sẽ trình bày cách Chỉnh sửa và Xóa dữ liệu khỏi RealTime Database Firebase cũng như lắng nghe kết quả thay công hay thất bại.

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

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

Realtime Database Firebase là một dịch vụ cơ sở dữ liệu thời gian thực hoạt động trên nền tảng đám mây được cung cấp bởi Google nhằm giúp các lập trình phát triển nhanh các ứng dụng có tương tác cơ sở dữ liệu (CRUD) một cách nhanh chóng và ngay tức thời (Realtime).

Thực ra ta cũng nên bày vẽ dịch Realtime Database Firebase ra Cơ sơ dữ liệu thời gian thực firebase

hay cũng không nên dịch Cloud ra chữ nền tảng đám mây. Cứ để Cloud là được rồi.

CRUD: Là 4 thao tác không thể thiếu với mọi ứng dụng có tương tác Cơ Sở Dữ liệu. C (Create- thêm mới), R (Retrieve – truy vấn xem dữ liệu), U (Update- cập nhật dữ liệu), D (Delete- xóa dữ liệu)

Khi có sự thay đổi dữ liệu trên Database Firebase thì ngay lập tức giao diện của bất kỳ thiết bị nào có sử dụng phần mềm này sẽ tự động cập nhật (gọi là Realtime):

Dữ liệu trên Database Firebase có định dạng JSON kiểu Gson.

Trong bài này Tui sẽ hướng dẫn các bạn cách sử dụng Firebase Database trong Android Studio như thế nào, và làm một ví dụ về hiển thị danh sách Danh bạ đẩy từ Firebase Server xuống.

Các bạn làm theo các bước hướng dẫn dưới đây (Tui hướng dẫn cho cả người chưa biết gì về Android nên sẽ làm chi tiết từ bước tạo Project):

Khởi động Android Studio:

Click Chọn “Start a new Android Studio Project”, lúc này cửa sổ yêu cầu tạo tên Project sẽ hiển thị ra, ta Đặt tên Project là RealtimeDatabaseFirebase:

Mục Application Name: Đặt tên cho ứng dụng RealtimeDatabaseFirebase

Mục Company Domain: Đặt tên theo domain của bạn, không có thì đặt đại nhưng phải viết thường hết nha, ví dụ ở trên Tui đặt là: communityuni.com

bản chất nó là package để tổ chức sắp xếp lại hệ thống các lớp trong Project, cũng là cơ sở để Google quản lý ứng dụng trên Google Play, Developer nữa.

Mục Project Location: Nơi lưu trữ dữ án

Lưu ý đừng có tick vào C++ hay Kotlin, vì bài hướng dẫn này Tui trình bày về Java

Sau cung cấp đủ các thông tin rồi thì bấm Next để qua bước tiếp theo:

Ở màn hình này ta chọn API là 26 nha rồi bấm Next:

Chọn Empty Activity rồi bấm Next

Bước này là thiết lập màn hình chính chạy: Activity Name là lớp Java để xử lý nghiệp vụ, Layout Name là giao diện cho màn hình đó, để mặc định vậy bấm FINISH

Như là ta đã tạo xong được Project trong Android Studio. Bây giờ bước tiếp theo là kết nối với Firebase để sử dụng Realtime Database Firebase. Ta làm như sau:

Vào menu Tools/ chọn Firbase, lúc này cửa sổ hướng dẫn cách sử Firebase sẽ được hiển thị ra ở góc phải của cửa sổ Android Studio:

Trong màn hình trên, Firebase cung cấp rất nhiều công cụ, tuy nhiên ta chỉ quan tâm tới Realtime Database thôi nha. Vì vậy ta nhấn vào Realtime Database:

Lúc này ta thấy nút “Save and retrieve data” hiển thị ra như hình trên. Bấm vào nó nha. Trình trợ giúp cung cấp cho ta 8 bước thao tác (bao gốm kết nối và hướng dẫn lập trình, ta dùng 2 -3 bước là đủ rồi):

bước 1: Connect your app to firebase
bước 2: Add the Realtime Database to our app
bước 3: Configure Firebase Database Rules
bước 4: Write to your database
bước 5: Read from your database
bước 6: Optional: Configure ProGuard
bước 7: Prepare for Launch
Bước 8: Next steps

Ở bước 1, ta nhấn vào nút “Connect to Firebase”, lúc này hệ thống sẽ yêu cầu chúng ta đăng nhập bằng tài khoản gmail:

Ta lựa chọn tài khoản email, ở trên có sẵn 2 email của Tui: duythanhcse@gmail.com và thanhtd@uel.edu.vn, nếu tui muốn làm các email khác thì nhấn vào Use another account
Sau khi chọn Email để đăng nhập, Google yêu cầu ta cung cấp một số quyền hạn như sau:

Ta nhấn Allow để tiếp tục, lúc này màn hình Developer của Android sẽ hiển thị ra:

Ở trên có 2 server: Firebase và Google Cloud, ta chọn Firebase ta có màn hình kết quả sau:

Chú ý góc phải trên cùng có nút “GO TO CONSOLE”, nhấn vào đây để vào trang quản trị của Firebase.

Lưu ý, Sau khi ta có màn hình trên, thì lúc này ở Project Android Studio sẽ tự động xuất hiện màn hình xác nhận kết nối Firebase (nhớ để ý để quay lại Android Studio xác nhận):

Phía trên là tên ứng dụng “RealtimeDatabaseFirebase”, Tui đăng nhập với email thanhtd@uel.edu.vn, phần existing chưa có vì ta mới làm. mục Country chọn Vietnam
sau đó nhấn nút “Connect to Firebase” để tiến hành kết nối:

Ta thấy màn hình nhỏ nhỏ ở góc phải bên dưới không, nó đang báo là đang két nối ứng dụng tới Firebase (Connecting app to Firebase). Ta chờ nha, chờ đợi trong hạnh phúc:

Khi kết nối thành công, bước 1 sẽ được bật đèn xanh như hình trên, và ta nhận được thông báo là thành công ở cửa sổ nhỏ nhỏ ở góc phải bên dưới Android Studio.

Một số lưu ý khi kết nối thất bại:

Giả sử ta gặp báo lỗi như hình dưới đây:

Thì có khả năng lỗi do các vấn đề sau:

– Mỗi một email như vậy, Google cho tạo khoảng 10 tới 12 kết nối Project, nên nó có thể thất bại nếu bạn đã vượt qua, lúc này tạo 1 email mới cho lẹ. Vì muốn xóa thì cũng phải chờ 1 tháng sau Google mới thực sự xác nhận xóa.

– Nếu không phải lỗi do vượt quá số lượng kết nối,  thì tiếp tục bấm lại nút “Connect to Firebase” lần nữa, nó xuất hiện ra thông báo này thì chọn Sync:

Hi vọng là các bạn không bị lỗi.

OK ta tiếp tục bước 2 nha.

Khi bước 1 thành công thì ta nhận được thông báo “Connected” màu xanh ở trên thấy không? tiếp theo ta nhấn vào “Add the Realtime Database to Your app” để đưa đưa cơ sở dữ liệu thời gian thực vào ứng dụng của mình:

Ta nhấn “Accept Changes” để hệ thống tự động đưa các thư viện vào build.gradle nha, nếu thành công ta sẽ thấy màu xanh được bật lên như dưới đây:

Bây giờ ta đợi Android studio Refresh nha, sau đó nếu có thông báo lỗi như dưới này:

Thì ta chỉ việc xóa :15.0.0 đằng sau đi nha (Tui có thử 16.0.1 hay 16.0.3 thấy ổn):

ta sửa:

implementation ‘com.google.firebase:firebase-database:16.0.3:15.0.0’

thành:

implementation ‘com.google.firebase:firebase-database:16.0.3’

rồi bấm Try Again lại:

nếu còn lỗi: Thì phải kiểm tra xem, coi chừng Android của bạn chưa cài Google Play Service, các bước kiểm tra và tải như sau:

Vào Menu Tools/ chọn SDK Manager:

Chọn  thẻ SDK Tools/ Tick vào Google Play Services rồi bấm  Apply chờ nó tải và cài đặt vào:

Ta chờ nó cài đặt Google Play Service nha, chờ nó cài xong là OK. Nếu mà vẫn bị lỗi thì chắc do ăn ở, mua máy mới luôn đi cho rồi.

Ta quay lại Website Firebase khi kết nối thành công để kiểm tra cũng như thao tác nha:

Nhìn thấy nút “GO TO CONSOLE” ở góc phải bên trên không? bấm vào nó:

Ta sẽ được dẫn tới màn hình dưới đây:

Ta thấy ứng dụng tên là RealtimeDatabaseFirebase xuất hiện ở trên không? nhấn vào nó (lưu ý là ở Android Studio kết nối thành công thì ở đây mới tự động thấy nó nha):

Hệ thống yêu cầu cấu hình chia sẻ dữ liệu, Ta bấm vào “Choose data sharing settings” chỗ dòng cảnh báo bên trên đó:

Ta tick chọn hết, tick I Accept… rồi nhấn FINISH

ta chờ hệ thống chạy một chút xíu sẽ xong và ra màn hình dưới đây:

Ta nhìn vào danh sách bên trái màn hình Website — > nhấn vào Database:

Sau khi nhấn vào Database, bên nội dung ta Kéo xuống nhìn thấy nhóm Realtime Database thì chọn “Create Database”:

Hệ thống cung cấp 2 mode:

  • Start In locked mode, dùng để chạy thực sử (khi đã release sản phẩm)
  • Start in Test mode, dùng cho Debug lúc mà ta đang phát triển phần mềm

Do ta đang test thì chọn start intest mode, khi nào xong thì chỉnh lại Locked mode sau:

Chọn Start in test mode xong thì bấm nút Enable nha. cấu hình thành công ta sẽ có màn hình với thông báo dưới đây:

Nó thông báo về bảo mật đó, vì ta đang test mà. Muốn chỉnh lại trong thẻ RULE:

OK, bây giờ ta nhập dữ liệu cho Database Realtime này. Có 2 cách nhập:

  • nhập trực tiếp vào màn hình Web
  • nhập bằng cách import 1 file JSON theo đúng cấu trúc

thấy chữ null ở trên không bạn? ta click vào chữ null rồi dán dữ liệu JSON theo đúng cấu trúc là OK:

Hoặc ở góc phải trên cùng nhấn vào …:

Có chức năng Export JSON là xuất dữ liệu ra file JSON, Import JSON là nhập 1 file dữ liệu JSON ở ngoài và hệ thống Database Realtime của Firebase.

Đây là cấu trúc của file dữ liệu ở trên, bạn lấy mẫu này cho lẹ nha,  dùng chức năng IMPORT JSON để lưu:

Tải JSON mẫu của Tui ở đây (realtimedatabasefirebase-cf3ad-export.json): https://www.mediafire.com/file/b5gsxfqal952ne6/realtimedatabasefirebase-cf3ad-export.json/file

Chọn Browse-> trỏ tải file tải về được, nhấn IMPORT -> Có kết quả như của Tui.

Như vậy ta đã làm xong bước kết nối Firebase, tạo cơ sở dữ liệu

Bước cuối cùng là ta truy suất Cơ sở dữ liệu Realtime này lên giao diện, thay đổi và quan sát nó cập nhật giao diện tức thời (Realtime):

Quay lại Android Studio:

Chính sửa Màn hình giao diện (activity_main.xml):

[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=".MainActivity">

<ListView
android:id="@+id/lvContact"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

[/code]

Màn hình chỉ có 1 ListView duy nhất, đặt Id là lvContact.

Trong bài này ta dùng hiển thị cơ bản thôi nha, bài sau Tui hướng dẫn nâng cao hơn.

Sau đó coding trong MainActivity.java như sau:

[code language=”java”]

package com.communityuni.realtimedatabasefirebase;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
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;

public class MainActivity extends AppCompatActivity {

ListView lvContact;
ArrayAdapter<String> adapter;
String TAG="FIREBASE";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
adapter=new ArrayAdapter<>(this,android.R.layout.simple_list_item_1);
lvContact=findViewById(R.id.lvContact);
lvContact.setAdapter(adapter);
//lấy đối tượng FirebaseDatabase
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
myRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
adapter.clear();
//vòng lặp để lấy dữ liệu khi có sự thay đổi trên Firebase
for (DataSnapshot data: dataSnapshot.getChildren())
{
//lấy key của dữ liệu
String key=data.getKey();
//lấy giá trị của key (nội dung)
String value=data.getValue().toString();
adapter.add(key+"\n"+value);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
}
});
}
}

[/code]

Chạy lên và ta có dữ liệu hiển thị như mong muốn:

Các bạn lưu ý, giờ trong Website Firebase, bạn thêm sửa xóa dữ liệ thì lập tức bất kỳ thiết bị Mobile nào đang sử dụng phần mềm nó sẽ thấy sự thay đổi này và cập nhật thời gian thực liền.

Như vậy Tui đã hướng dẫn các bạn hoàn chỉnh các bước làm thế nào để tạo một Project Android sử dụng Cơ sở dữ liệu thời gian thực, thao tác Realtime Database, cách kết nối, lập trình…

Source code của bài này: https://www.mediafire.com/file/r1bihzvc91zpa3n/RealtimeDatabaseFirebase.rar/file

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