1. Trước khi bắt đầu
Lớp học lập trình này giới thiệu một ứng dụng mới có tên là Forage (Hái lượm hoa quả) mà bạn sẽ tự mình xây dựng. Trong lớp học lập trình này, bạn sẽ được hướng dẫn từng bước để hoàn thành dự án xây dựng ứng dụng Forage, bao gồm cả quá trình thiết lập và kiểm thử dự án trong Android Studio.
Điều kiện tiên quyết
- Dự án này dành cho những học viên đã hoàn thành Bài 5 trong khoá học Kotlin cơ bản cho Android.
Sản phẩm bạn sẽ tạo ra
- Sử dụng thư viện cơ sở dữ liệu Room để tăng tính liên tục cho ứng dụng hiện có bằng cách triển khai các thực thể, DAO, ViewModel và lớp cơ sở dữ liệu.
Bạn cần có
- Một máy tính đã cài đặt Android Studio.
2. Tổng quan về ứng dụng đã hoàn thiện
Ứng dụng Forage (Hái lượm hoa quả) hoàn thiện cho phép người dùng theo dõi đồ vật (như thức ăn) mà họ kiếm được trong tự nhiên. Dữ liệu này vẫn tồn tại giữa các phiên bằng cách dùng Room. Bạn sẽ vận dụng kiến thức học được về Room và thực hiện các thao tác đọc, ghi, cập nhật và xoá trên cơ sở dữ liệu để tăng tính liên tục cho ứng dụng Forage. Dưới đây là thông tin mô tả về ứng dụng hoàn chỉnh và chức năng của ứng dụng.
Trong lần đầu khởi chạy ứng dụng, người dùng sẽ nhìn thấy một màn hình trống chứa khung hiển thị tái sinh (recycler view) cho thấy các mặt hàng kiếm được. Đồng thời, ở góc dưới cùng bên phải của ứng dụng sẽ có một nút tròn nổi, cho phép thêm các mặt hàng mới.
Khi thêm một mục mới, người dùng có thể chỉ định tên, nơi tìm thấy cũng như ghi chú bổ sung. Ngoài ra, bạn sẽ thấy một hộp đánh dấu cho biết loại thực phẩm đó đang trong vào mùa hay không.
Sau khi bạn thêm một mục, mục đó sẽ xuất hiện trong khung nhìn tái sinh trên màn hình đầu tiên.
Nhấn vào một mục, bạn sẽ thấy màn hình chi tiết cho thấy tên, vị trí và ghi chú.
Biểu tượng dấu cộng trên nút tròn nổi cũng chuyển sang biểu tượng chỉnh sửa. Khi nhấn vào nút này, bạn sẽ được dẫn đến một màn hình cho phép chỉnh sửa tên, vị trí, thông tin ghi chú và hộp đánh dấu "in season" ("đang trong mùa"). Khi nhấn vào nút xoá, mục này sẽ bị xoá khỏi cơ sở dữ liệu.
Phần giao diện người dùng của ứng dụng này đã hoàn thiện, nhiệm vụ của bạn bây giờ là tăng tính liên tục của ứng dụng trên cơ sở kiến thức bạn nắm được về Room. Ứng dụng sẽ cho phép người dùng đọc, ghi, cập nhật và xoá các loại thực phẩm khỏi cơ sở dữ liệu.
3. Bắt đầu
Tải mã dự án xuống
Lưu ý tên thư mục là android-basics-kotlin-forage-app
. Chọn thư mục này khi bạn mở dự án trong Android Studio.
Để lấy mã nguồn cho lớp học lập trình này và mở đoạn mã đó trong Android Studio, hãy thực hiện các bước sau.
Lấy mã
- Nhấp vào URL được cung cấp. Thao tác này sẽ mở trang GitHub của dự án trong một trình duyệt.
- Trên trang GitHub của dự án, hãy nhấp vào nút Code (Mã), một hộp thoại sẽ xuất hiện.
- Trong hộp thoại này, hãy nhấp vào nút Download ZIP (Tải tệp ZIP xuống) để lưu dự án vào máy tính. Chờ quá trình tải xuống hoàn tất.
- Xác định vị trí của tệp trên máy tính (thường nằm trong thư mục Downloads (Tệp đã tải xuống)).
- Nhấp đúp vào tệp ZIP để giải nén. Thao tác này sẽ tạo một thư mục mới chứa các tệp dự án.
Mở dự án trong Android Studio
- Khởi động Android Studio.
- Trong cửa sổ Welcome to Android Studio (Chào mừng bạn đến với Android Studio), hãy nhấp vào Open an existing Android Studio project (Mở một dự án hiện có trong Android Studio).
Lưu ý: Nếu Android Studio đã mở sẵn thì thay vào đó, hãy chọn tuỳ chọn sau đây trong trình đơn File > New > Import Project (Tệp > Mới > Nhập dự án).
- Trong hộp thoại Import Project (Nhập dự án), hãy chuyển đến nơi chứa thư mục dự án đã giải nén (thường nằm trong thư mục Downloads (Tệp đã tải xuống)).
- Nhấp đúp vào thư mục dự án đó.
- Chờ Android Studio mở dự án.
- Nhấp vào nút Run (Chạy) để xây dựng và chạy ứng dụng. Hãy đảm bảo ứng dụng được dựng như mong đợi.
- Duyệt qua các tệp dự án trong cửa sổ công cụ Project (Dự án) để xem cách ứng dụng được thiết lập.
4. Thiết lập dự án để sử dụng thư viện Room
Định nghĩa thực thể Forageable
Dự án đã tạo một lớp Forageable
để định nghĩa dữ liệu của ứng dụng (model.Forageable.kt). Lớp này có một số thuộc tính: id
, name
, address
, inSeason
và notes
.
data class Forageable(
val id: Long = 0,
val name: String,
val address: String,
val inSeason: Boolean,
val notes: String?
)
Tuy nhiên, để có thể lưu trữ dữ liệu cố định bằng lớp này, bạn cần chuyển đổi lớp này thành một thực thể Room.
- Chú thích lớp này bằng cú pháp
@Entity
với tên bảng là"forageable_database"
. - Đặt thuộc tính
id
làm khoá chính. Khoá chính sẽ được tạo tự động. - Đặt tên cột cho thuộc tính
inSeason
thành"in_season"
.
Triển khai DAO
Có thể đoán được rằng ForageableDao
(data.ForageableDao.kt) là nơi định nghĩa phương thức đọc và ghi trên cơ sở dữ liệu bạn sẽ truy cập trong mô hình xem (view model). DAO chỉ là một giao diện do bạn định nghĩa, vì vậy thực ra bạn không cần viết mã nguồn để triển khai các phương thức này. Thay vào đó, bạn nên sử dụng chú thích Room để chỉ định truy vấn SQL khi cần thiết.
Trong giao diện ForageableDao
, bạn cần thêm 5 phương thức.
- Phương thức
getForageables()
trả về mộtFlow<List<Forageable>>
cho tất cả các hàng trong cơ sở dữ liệu. - Phương thức
getForageable(id: Long)
trả vềFlow<Forageable>
phù hợp vớiid
đã chỉ định. - Phương thức
insert(forageable: Forageable)
chèn mộtForageable
mới vào cơ sở dữ liệu. - Phương thức
update(forageable: Forageable)
lấyForageable
hiện có làm tham số và cập nhật hàng tương ứng. - Phương thức
delete(forageable: Forageable)
lấyForageable
làm tham số và xoá tham số đó khỏi cơ sở dữ liệu.
Triển khai view model
ForageableViewModel
(ui.viewmodel.ForageableViewModel.kt) đã được triển khai một phần, bạn cần thêm chức năng truy cập phương thức DAO để có thể đọc và ghi dữ liệu. Thực hiện các bước sau đây để triển khai ForageableViewModel
.
- Truyền một thực thể của
ForageableDao
vào hàm khởi tạo của lớp này dưới dạng tham số. - Tạo biến thuộc kiểu
LiveData<List<Forageable>>
để lấy toàn bộ danh sách thực thểForageable
bằng DAO, sau đó chuyển đổi kết quả thànhLiveData
. - Tạo một phương thức với tham số là mã nhận dạng (kiểu
Long
) rồi gọi phương thứcgetForageable()
trên DAO để trả vềLiveData<Forageable>
, sau đó chuyển đổi kết quả thànhLiveData
. - Trong phương thức
addForageable()
, hãy khởi chạy một coroutine bằngviewModelScope
rồi sử dụng DAO để chèn thực thểForageable
vào cơ sở dữ liệu. - Trong phương thức
updateForageable()
, hãy sử dụng DAO để cập nhật thực thểForageable
. - Trong phương thức
deleteForageable()
, hãy sử dụng DAO để cập nhật thực thểForageable
. - Tạo một
ViewModelFactory
để có thể tạo một thực thể củaForageableViewModel
với tham số là hàm khởi tạoForageableDao
.
Triển khai lớp Database
Lớp ForageDatabase
(data.ForageDatabase.kt
) mới thực sự là lớp cho Room thấy các thực thể và DAO. Hãy triển khai lớp ForageDatabase
theo mô tả dưới đây.
- Thực thể:
Forageable
- Phiên bản:
1
- exportSchema:
false
- Bên trong lớp
ForageDatabase
, hãy đưa vào một hàm abstract để trả về mộtForageableDao
- Bên trong lớp
ForageDatabase
, hãy định nghĩa một đối tượng đồng hành có biến private tên làINSTANCE
và một hàmgetDatabase()
trả về singletonForageDatabase
.
- Trong lớp
BaseApplication
, hãy tạo một thuộc tínhdatabase
trả về một thực thểForageDatabase
sử dụng phương pháp khởi tạo từng phần (lazy initialization).
5. Duy trì và đọc dữ liệu qua các phân đoạn
Sau khi thiết lập các thực thể, DAO, mô hình hiển thị và định nghĩa lớp cơ sở dữ liệu để cho Room thấy, bạn chỉ cần sửa đổi các Mảnh (fragment) để truy cập vào mô hình hiển thị. Bạn cần thay đổi ba tệp, mỗi tệp cho một màn hình trong ứng dụng.
Danh sách hoa quả hái lượm được (Forageable)
Màn hình danh sách hoa quả hái lượm được chỉ có hai yêu cầu: tham chiếu đến view model và quyền truy cập danh sách đầy đủ các loại hoa quả đã hái lượm được. Thực hiện các hoạt động sau trong ui.ForageableListFragment.kt.
- Lớp này đã có một thuộc tính
viewModel
. Tuy nhiên, thuộc tính này chưa sử dụng hàm nhà máy (factory) bạn đã định nghĩa ở bước trước. Trước hết, bạn cần tái cấu trúc phần khai báo để sử dụngForageableViewModelFactory
.
private val viewModel: ForageableViewModel by activityViewModels {
ForageableViewModelFactory(
(activity?.application as BaseApplication).database.foragableDao()
)
}
- Sau đó, trong
onViewCreated()
, hãy quan sát thuộc tínhallForageables
quaviewModel
rồi gọisubmitList()
trên trình chuyển đổi để điền danh sách này vào thời điểm thích hợp.
Màn hình chi tiết hoa quả hái lượm được
Bạn sẽ thực hiện các bước tương tự cho danh sách chi tiết trong ui/ForageableDetailFragment.kt.
- Chuyển đổi thuộc tính
viewModel
để khởi chạyForageableViewModelFactory
cho chính xác. - Trong
onViewCreated()
, hãy gọigetForageable()
trên view model, truyền vào giá trịid
để nhận thực thểForageable
. Quan sát dữ liệu trực tiếp rồi thiết lập kết quả cho thuộc tínhforageable
, sau đó gọibindForageable()
để cập nhật giao diện người dùng.
Thêm và chỉnh sửa màn hình hoa quả hái lượm được
Cuối cùng, bạn cần thực hiện các bước tương tự trong ui.AddForageableFragment.kt. Hãy lưu ý rằng màn hình này cũng chịu trách nhiệm cập nhật và xoá các thực thể. Tuy nhiên, các phương thức này đã được gọi ở nơi phù hợp trong view model. Bạn chỉ cần thực hiện hai thay đổi trong tệp này.
- Một lần nữa, hãy tái cấu trúc thuộc tính
viewModel
để sử dụngForageableViewModelFactory
. - Trong
onViewCreated()
, trong khối lệnh if trước khi thiết lập chế độ hiển thị cho nút xoá, hãy gọigetForageable()
trên mô hình hiển thị, truyền vào giá trịid
và đặt kết quả thành thuộc tínhforageable
.
Đó là tất cả những gì cần làm trong các phân đoạn. Bây giờ, bạn có thể chạy ứng dụng và thấy rằng tất cả chức năng đều hoạt động liên tục.
6. Hướng dẫn kiểm thử
Chạy kiểm thử
Để chạy kiểm thử, bạn có thể làm theo một trong những cách sau.
Đối với một trường hợp kiểm thử duy nhất, hãy mở lớp trường hợp kiểm thử (test case) PersistenceInstrumentationTests.kt
rồi nhấp vào mũi tên màu xanh lục ở bên trái phần khai báo lớp. Sau đó, chọn tuỳ chọn Run (Chạy) trên trình đơn. Thao tác này sẽ chạy tất cả chương trình kiểm thử trong trường hợp kiểm thử đó.
Thường thì bạn chỉ muốn chạy một kiểm thử duy nhất, chẳng hạn như trong tình huống chỉ có một kiểm thử không đạt yêu cầu còn những kiểm thử còn lại thì đạt. Bạn có thể chạy một kiểm thử duy nhất tương tự như cách thực hiện trên toàn bộ trường hợp kiểm thử. Sử dụng mũi tên màu xanh lục rồi chọn tuỳ chọn Run (Chạy).
Nếu có nhiều trường hợp kiểm thử, bạn cũng có thể chạy toàn bộ bộ kiểm thử. Tương tự như cách chạy ứng dụng, bạn có thể thấy tuỳ chọn này trên trình đơn Run (Chạy).
Lưu ý rằng theo mặc định, Android Studio sẽ chuyển đến mục tiêu gần nhất mà bạn đã chạy (ứng dụng, mục tiêu kiểm thử, v.v.). Do đó, nếu trình đơn vẫn cho thấy Run > Run 'app' (Chạy > Chạy "ứng dụng"), thì bạn có thể chạy mục tiêu kiểm thử này bằng cách chọn Run > Run (Chạy > Chạy).
Sau đó, hãy chọn mục tiêu kiểm thử trên trình đơn bật lên.