Lớp học lập trình này nằm trong khóa học về Khái niệm cơ bản về Android Kotlin. Bạn sẽ nhận được nhiều giá trị nhất từ khóa học này nếu bạn làm việc qua các lớp học lập trình theo trình tự. Tất cả các lớp học lập trình trong khóa học đều có trên trang đích của các lớp học lập trình cơ bản về Android Kotlin.
Giới thiệu
Hầu hết các ứng dụng đều có dữ liệu cần được giữ lại, ngay cả sau khi người dùng đóng ứng dụng. Ví dụ: ứng dụng có thể lưu trữ danh sách phát, kho hàng vật phẩm, hồ sơ chi phí và thu nhập, danh mục chòm sao hoặc dữ liệu về giấc ngủ theo thời gian. Thông thường, bạn sẽ dùng cơ sở dữ liệu để lưu trữ dữ liệu ổn định.
Room
là một thư viện cơ sở dữ liệu thuộc Jetpack của Android. Room
xử lý nhiều việc nhà khi thiết lập và định cấu hình cơ sở dữ liệu, đồng thời giúp ứng dụng của bạn tương tác với cơ sở dữ liệu bằng những lệnh gọi hàm thông thường. Về cơ bản, Room
là một lớp trừu tượng nằm ở đầu cơ sở dữ liệu SQLite. Room
Thuật ngữ và cú pháp truy vấn cho những cụm từ tìm kiếm phức tạp hơn, hãy làm theo mô hình SQLite.
Hình ảnh dưới đây cho thấy cách cơ sở dữ liệu Room
phù hợp với cấu trúc tổng thể được đề xuất trong khóa học này.
Kiến thức bạn cần có
Bạn cần thông thạo:
- Xây dựng giao diện người dùng (UI) cơ bản cho ứng dụng Android
- Sử dụng hoạt động, mảnh và chế độ xem.
- Di chuyển giữa các mảnh và sử dụng Safe Args (trình bổ trợ Gradle) để chuyển dữ liệu giữa các mảnh.
- Xem các mô hình, nhà máy sản xuất mô hình xem,
LiveData
và các đối tượng tiếp nhận dữ liệu. Các chủ đề về Thành phần cấu trúc này được đề cập trong một lớp học lập trình trước đây trong khóa học này. - Kiến thức cơ bản về cơ sở dữ liệu SQL và ngôn ngữ SQLite. Hãy xem SQLite Primer để xem tổng quan nhanh hoặc xem lại.
Kiến thức bạn sẽ học được
- Cách tạo và tương tác với cơ sở dữ liệu của
Room
để duy trì dữ liệu. - Cách tạo lớp dữ liệu xác định một bảng trong cơ sở dữ liệu.
- Cách sử dụng đối tượng truy cập dữ liệu (DAO) để ánh xạ các hàm Kotlin đến truy vấn SQL.
- Cách kiểm tra xem cơ sở dữ liệu của bạn có đang hoạt động hay không.
Bạn sẽ thực hiện
- Tạo cơ sở dữ liệu
Room
có giao diện cho dữ liệu về giấc ngủ vào mỗi đêm. - Kiểm tra cơ sở dữ liệu bằng cách sử dụng các quy trình kiểm tra được cung cấp.
Trong lớp học lập trình này, bạn xây dựng phần cơ sở dữ liệu của một ứng dụng theo dõi chất lượng giấc ngủ. Ứng dụng sẽ dùng cơ sở dữ liệu để lưu trữ dữ liệu về giấc ngủ.
Ứng dụng có hai màn hình, được biểu thị bằng các mảnh, như minh họa trong hình bên dưới.
Màn hình đầu tiên (hiển thị ở bên trái) có các nút để bắt đầu và dừng theo dõi. Màn hình hiển thị tất cả dữ liệu giấc ngủ của người dùng. Nút Xóa xóa vĩnh viễn tất cả dữ liệu mà ứng dụng đã thu thập cho người dùng.
Màn hình thứ hai hiển thị ở bên phải, cho biết mức chọn điểm xếp hạng chất lượng giấc ngủ. Trong ứng dụng, điểm xếp hạng được biểu thị bằng số. Để phát triển, ứng dụng sẽ hiển thị cả biểu tượng khuôn mặt và giá trị tương đương bằng số.
Luồng người dùng như sau:
- Người dùng mở ứng dụng và hiển thị màn hình theo dõi giấc ngủ.
- Người dùng nhấn vào nút Bắt đầu. Thao tác này sẽ ghi lại thời gian bắt đầu và hiển thị thời gian đó. Nút Bắt đầu đã tắt và nút Dừng.
- Người dùng nhấn vào nút Dừng. Thao tác này sẽ ghi lại thời gian kết thúc và mở màn hình chất lượng giấc ngủ.
- Người dùng chọn một biểu tượng chất lượng giấc ngủ. Màn hình sẽ đóng lại và màn hình theo dõi hiển thị thời gian ngủ và chất lượng giấc ngủ. Nút Dừng bị tắt và nút Bắt đầu đang bật. Ứng dụng đã sẵn sàng cho một đêm khác.
- Nút Xóa được bật bất cứ khi nào có dữ liệu trong cơ sở dữ liệu. Khi người dùng nhấn vào nút Xóa, tất cả dữ liệu của họ sẽ bị xóa mà không cần truy cập lại – không có "Bạn có chắc chắn{5}quot; tin nhắn không.
Ứng dụng này dùng một cấu trúc đơn giản như trong bối cảnh của cấu trúc đầy đủ. Ứng dụng này chỉ sử dụng các thành phần sau:
- Bộ điều khiển giao diện người dùng
- Xem mô hình và
LiveData
- Cơ sở dữ liệu Phòng
Bước 1: Tải xuống và chạy ứng dụng dành cho người mới bắt đầu
- Tải ứng dụng TrackMySleepquality-Starter xuống từ GitHub.
- Tạo và chạy ứng dụng. Ứng dụng này hiển thị giao diện người dùng cho mảnh
SleepTrackerFragment
nhưng không hiển thị dữ liệu. Các nút không phản hồi khi nhấn.
Bước 2: Kiểm tra ứng dụng dành cho người mới bắt đầu
- Hãy xem tệp Gradle:
- Tệp Gradle dự án
Trong tệpbuild.gradle
cấp dự án, hãy chú ý đến các biến chỉ định phiên bản thư viện. Các phiên bản được dùng trong ứng dụng dành cho người mới bắt đầu hoạt động hiệu quả với nhau và hoạt động tốt với ứng dụng này. Khi bạn hoàn tất lớp học lập trình này, Android Studio có thể nhắc bạn cập nhật một số phiên bản. Bạn có quyền quyết định xem bạn muốn cập nhật hay giữ lại các phiên bản trong ứng dụng. Nếu bạn gặp lỗi "strange" lỗi biên dịch, hãy thử sử dụng kết hợp các phiên bản thư viện mà ứng dụng giải pháp cuối cùng sử dụng. - Tệp Gradle mô-đun. Lưu ý đến các phần phụ thuộc được cung cấp cho mọi thư viện Android Jetpack, bao gồm cả
Room
, và các phần phụ thuộc cho coroutine.
- Hãy xem các gói và giao diện người dùng. Ứng dụng được sắp xếp theo chức năng. Gói này chứa các tệp giữ chỗ mà bạn sẽ thêm mã trong suốt các lớp học lập trình này.
- Gói
database
, cho tất cả các mã liên quan đến cơ sở dữ liệu củaRoom
. - Các gói
sleepquality
vàsleeptracker
chứa mảnh, mô hình xem và trạng thái ban đầu của mô hình chế độ xem cho mỗi màn hình.
- Hãy xem
Util.kt
tệp, có chứa hàm giúp hiển thị dữ liệu về chất lượng giấc ngủ. Một số mã được nhận xét do mã này tham chiếu đến một mô hình chế độ xem mà bạn tạo sau này. - Hãy xem thư mục Kiểm tra android (
SleepDatabaseTest.kt
). Bạn sẽ dùng thử nghiệm này để xác minh rằng cơ sở dữ liệu hoạt động như dự kiến.
Trong Android, dữ liệu được trình bày trong lớp dữ liệu, đồng thời dữ liệu được truy cập và sửa đổi bằng các lệnh gọi hàm. Tuy nhiên, trong thế giới cơ sở dữ liệu, bạn cần có thực thể và truy vấn.
- Thực thể đại diện cho một đối tượng hoặc khái niệm và các thuộc tính của đối tượng đó để lưu trữ trong cơ sở dữ liệu. Một lớp thực thể xác định bảng và mỗi thực thể của lớp đó đại diện cho một hàng trong bảng. Mỗi thuộc tính xác định một cột. Trong ứng dụng của bạn, đối tượng này sẽ lưu giữ thông tin về đêm ngủ.
- Truy vấn là một yêu cầu về dữ liệu hoặc thông tin từ bảng cơ sở dữ liệu, hoặc kết hợp các bảng hoặc yêu cầu thực hiện một hành động đối với dữ liệu. Truy vấn phổ biến là lấy, chèn và cập nhật các thực thể. Ví dụ: bạn có thể truy vấn tất cả các đêm ngủ được ghi lại, được sắp xếp theo thời gian bắt đầu.
Room
sẽ trợ giúp bạn trong việc chuyển các lớp dữ liệu Kotlin sang các thực thể có thể được lưu trữ trong bảng SQLite, và từ việc khai báo hàm cho đến các truy vấn SQL.
Bạn phải xác định mỗi thực thể là một lớp dữ liệu được chú thích và các hoạt động tương tác là một giao diện được chú thích, một đối tượng truy cập dữ liệu (DAO). Room
sử dụng các lớp có chú thích này để tạo bảng trong cơ sở dữ liệu và truy vấn hoạt động trên cơ sở dữ liệu.
Bước 1: Tạo thực thể Sleepnight
Trong nhiệm vụ này, bạn xác định một đêm ngủ là lớp dữ liệu có chú thích.
Đối với giấc ngủ một đêm, bạn cần ghi lại thời gian bắt đầu, thời gian kết thúc và điểm xếp hạng chất lượng.
Và bạn cần một mã nhận dạng để xác định duy nhất đêm.
- Trong gói
database
, hãy tìm và mở tệpSleepNight.kt
. - Tạo lớp dữ liệu
SleepNight
có các thông số cho một mã nhận dạng, thời gian bắt đầu (tính bằng mili giây), thời gian kết thúc (tính bằng mili giây) và điểm xếp hạng chất lượng giấc ngủ bằng số.
- Bạn phải khởi tạo
sleepQuality
, vì vậy, hãy đặt giá trị thành-1
, cho biết rằng chưa thu thập dữ liệu chất lượng nào. - Bạn cũng phải khởi tạo thời gian kết thúc. Đặt thời gian bắt đầu để báo hiệu rằng chưa có thời gian kết thúc nào được ghi lại.
data class SleepNight(
var nightId: Long = 0L,
val startTimeMilli: Long = System.currentTimeMillis(),
var endTimeMilli: Long = startTimeMilli,
var sleepQuality: Int = -1
)
- Trước khi khai báo lớp, hãy chú thích lớp dữ liệu bằng
@Entity
. Đặt tên cho bảng làdaily_sleep_quality_table
. Đối số chotableName
là không bắt buộc, nhưng nên dùng. Bạn có thể tra cứu các đối số khác trong tài liệu.
Nếu được nhắc, hãy nhậpEntity
và tất cả chú thích khác từ thư việnandroidx
.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)
- Để khai báo
nightId
làm khoá chính, hãy chú giải thuộc tínhnightId
bằng@PrimaryKey
. Hãy thiết lập tham sốautoGenerate
thànhtrue
đểRoom
tạo giá trị nhận dạng cho mỗi thực thể. Điều này đảm bảo rằng mã nhận dạng cho mỗi đêm là duy nhất.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...
- Chú giải các thuộc tính còn lại bằng
@ColumnInfo
. Tuỳ chỉnh tên thuộc tính bằng cách sử dụng các tham số như dưới đây.
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,
@ColumnInfo(name = "start_time_milli")
val startTimeMilli: Long = System.currentTimeMillis(),
@ColumnInfo(name = "end_time_milli")
var endTimeMilli: Long = startTimeMilli,
@ColumnInfo(name = "quality_rating")
var sleepQuality: Int = -1
)
- Tạo và chạy mã của bạn để đảm bảo mã không có lỗi.
Trong nhiệm vụ này, bạn xác định một đối tượng truy cập dữ liệu (DAO). Trên Android, DAO cung cấp các phương thức thuận tiện để chèn, xóa và cập nhật cơ sở dữ liệu.
Khi sử dụng cơ sở dữ liệu của Room
, bạn truy vấn cơ sở dữ liệu bằng cách xác định và gọi các hàm Kotlin trong mã của mình. Các hàm Kotlin này liên kết với các truy vấn SQL. Bạn xác định các mối liên kết này trong DAO bằng chú thích và Room
tạo mã cần thiết.
Hãy xem DAO là một giao diện tùy chỉnh để truy cập vào cơ sở dữ liệu của bạn.
Đối với các thao tác cơ sở dữ liệu phổ biến, thư viện Room
cung cấp các chú giải thuận tiện như @Insert
, @Delete
và @Update
. Chú giải @Query
dành cho các thao tác khác. Bạn có thể viết bất kỳ truy vấn nào được SQLite hỗ trợ.
Ngoài ra, khi bạn tạo truy vấn trong Android Studio, trình biên dịch sẽ kiểm tra các truy vấn SQL của bạn để tìm lỗi cú pháp.
Đối với cơ sở dữ liệu trình theo dõi giấc ngủ về đêm, bạn cần có thể làm như sau:
- Chèn đêm mới.
- Cập nhật đêm hiện có để cập nhật thời gian kết thúc và điểm xếp hạng chất lượng.
- Nhận một đêm cụ thể dựa trên khóa của phòng.
- Xem tất cả các đêm để có thể giới thiệu các chương trình này.
- Xem đêm gần đây nhất.
- Xoá tất cả các mục trong cơ sở dữ liệu.
Bước 1: Tạo DAIDatabase DAO
- Trong gói
database
, hãy mởSleepDatabaseDao.kt
. - Lưu ý rằng
interface
SleepDatabaseDao
được chú thích bằng@Dao
. Bạn cần chú thích tất cả DAO bằng từ khóa@Dao
.
@Dao
interface SleepDatabaseDao {}
- Bên trong phần nội dung của giao diện, hãy thêm chú giải
@Insert
. Bên dưới@Insert
, hãy thêm một hàminsert()
lấy một thực thể của lớpEntity
SleepNight
làm đối số của lớp đó.
Chính xác.Room
sẽ tạo tất cả mã cần thiết để chènSleepNight
vào cơ sở dữ liệu. Khi bạn gọiinsert()
từ mã Kotlin,Room
sẽ thực thi một truy vấn SQL để chèn thực thể đó vào cơ sở dữ liệu. (Lưu ý: Bạn có thể gọi hàm bất kỳ thứ gì bạn muốn.)
@Insert
fun insert(night: SleepNight)
- Thêm chú giải
@Update
có hàmupdate()
cho mộtSleepNight
. Thực thể được cập nhật là thực thể có cùng khóa với thực thể đã chuyển vào. Bạn có thể cập nhật một số hoặc tất cả thuộc tính khác của thực thể.
@Update
fun update(night: SleepNight)
Không có chú giải tiện lợi cho chức năng còn lại. Vì vậy, bạn phải sử dụng chú giải @Query
và cung cấp các truy vấn SQLite.
- Thêm chú thích
@Query
bằng hàmget()
lấy đối sốLong
key
và trả vềSleepNight
có thể có giá trị null. Bạn sẽ thấy lỗi thông số bị thiếu.
@Query
fun get(key: Long): SleepNight?
- Truy vấn được cung cấp dưới dạng một tham số chuỗi cho chú thích. Thêm một tham số vào
@Query
. Đặt thànhString
thành một truy vấn SQLite.
- Chọn tất cả các cột qua
daily_sleep_quality_table
WHERE
nightId
khớp với đối số:key
.
Hãy chú ý đến:key
. Bạn sử dụng ký hiệu dấu hai chấm trong truy vấn để tham chiếu các đối số trong hàm.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
- Thêm một
@Query
khác có hàmclear()
và truy vấn SQLite vàoDELETE
mọi thứ từdaily_sleep_quality_table
. Truy vấn này không xóa bảng.
Chú thích@Delete
xóa một mục và bạn có thể sử dụng@Delete
cũng như cung cấp danh sách các đêm cần xóa. Hạn chế của việc này là bạn cần phải tìm nạp hoặc biết rõ những gì trong bảng. Chú thích@Delete
rất phù hợp để xóa các mục cụ thể nhưng không hiệu quả để xóa tất cả các mục khỏi bảng.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
- Thêm một
@Query
bằng hàmgetTonight()
. ĐặtSleepNight
dogetTonight()
trả về có thể có giá trị null để hàm có thể xử lý trường hợp bảng trống. (Bảng trống ở đầu và sau khi dữ liệu bị xóa.)
Để lấy "tonight" từ cơ sở dữ liệu, hãy viết truy vấn SQLite trả về phần tử đầu tiên của danh sách kết quả được sắp xếp theonightId
theo thứ tự giảm dần. Hãy dùngLIMIT 1
để chỉ trả về một phần tử.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?
- Thêm
@Query
có hàmgetAllNights()
:
- Yêu cầu truy vấn SQLite trả về mọi cột từ
daily_sleep_quality_table
, theo thứ tự giảm dần. - Yêu cầu
getAllNights()
trả về danh sách các thực thểSleepNight
dưới dạngLiveData
.Room
giúpLiveData
này luôn cập nhật, nghĩa là bạn chỉ cần xác định rõ ràng dữ liệu một lần. - Có thể bạn cần nhập
LiveData
từandroidx.lifecycle.LiveData
.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
fun getAllNights(): LiveData<List<SleepNight>>
- Dù bạn sẽ không nhận thấy thay đổi nào, nhưng hãy chạy ứng dụng của bạn để đảm bảo ứng dụng không có lỗi.
Trong việc cần làm này, bạn tạo một cơ sở dữ liệu Room
sử dụng Entity
và DAO mà bạn đã tạo trong việc cần làm trước đó.
Bạn cần tạo một lớp lưu giữ cơ sở dữ liệu trừu tượng, được chú thích bằng @Database
. Lớp này có một phương thức tạo thực thể của cơ sở dữ liệu nếu cơ sở dữ liệu không tồn tại hoặc trả về thông tin tham chiếu đến cơ sở dữ liệu hiện có.
Việc thu thập cơ sở dữ liệu Room
khá phức tạp, vì vậy, bạn nên thực hiện quy trình chung này trước khi bắt đầu sử dụng mã:
- Tạo một lớp
public abstract
đểextends RoomDatabase
. Lớp này đóng vai trò là chủ sở hữu cơ sở dữ liệu. Lớp này là trừu tượng vìRoom
tạo ra cách triển khai cho bạn. - Chú giải lớp này bằng
@Database
. Trong các đối số, hãy khai báo thực thể cho cơ sở dữ liệu và đặt số phiên bản. - Bên trong một đối tượng
companion
, hãy xác định một phương thức hoặc thuộc tính trừu tượng trả vềSleepDatabaseDao
.Room
sẽ tạo nội dung cho bạn. - Bạn chỉ cần một phiên bản của cơ sở dữ liệu
Room
cho toàn bộ ứng dụng, do đó, hãy đặtRoomDatabase
thành một singleton. - Dùng trình tạo cơ sở dữ liệu của
Room
để tạo cơ sở dữ liệu chỉ khi cơ sở dữ liệu không tồn tại. Nếu không, hãy trả về cơ sở dữ liệu hiện có.
Bước 1: Tạo cơ sở dữ liệu
- Trong gói
database
, hãy mởSleepDatabase.kt
. - Trong tệp, hãy tạo một lớp
abstract
có tên làSleepDatabase
, mở rộng đó làRoomDatabase
.
Hãy chú thích lớp đó bằng@Database
.
@Database()
abstract class SleepDatabase : RoomDatabase() {}
- Bạn sẽ thấy lỗi một số thực thể và thông số phiên bản bị thiếu. Chú giải
@Database
yêu cầu một số đối số đểRoom
có thể xây dựng cơ sở dữ liệu.
- Hãy cung cấp
SleepNight
làm mục duy nhất có danh sáchentities
. - Đặt
version
làm1
. Bất cứ khi nào thay đổi giản đồ, bạn sẽ phải tăng số phiên bản. - Thiết lập
exportSchema
thànhfalse
để không giữ lại các bản sao lưu nhật ký phiên bản giản đồ.
entities = [SleepNight::class], version = 1, exportSchema = false
- Cơ sở dữ liệu cần biết về DAO. Bên trong phần nội dung của lớp, hãy khai báo một giá trị trừu tượng trả về
SleepDatabaseDao
. Bạn có thể có nhiều DAO.
abstract val sleepDatabaseDao: SleepDatabaseDao
- Ở bên dưới, hãy xác định một đối tượng
companion
. Đối tượng companion cho phép khách hàng truy cập vào các phương thức để tạo hoặc lấy cơ sở dữ liệu mà không cần tạo thực thể lớp. Vì mục đích duy nhất của lớp này là cung cấp cơ sở dữ liệu, nên không có lý do gì để tạo thực thể của cơ sở dữ liệu này.
companion object {}
- Bên trong đối tượng
companion
, hãy khai báoINSTANCE
(biến riêng tư có thể mang giá trị rỗng) cho cơ sở dữ liệu và khởi tạo biến đó đếnnull
. BiếnINSTANCE
sẽ lưu giữ thông tin tham chiếu đến cơ sở dữ liệu sau khi thông tin được tạo. Điều này giúp bạn tránh được việc liên tục mở kết nối tới cơ sở dữ liệu. Việc này sẽ tốn kém.
Chú giải INSTANCE
bằng @Volatile
. Giá trị của biến volatile sẽ không bao giờ được lưu vào bộ nhớ đệm và tất cả lượt ghi và đọc sẽ xuất phát và trở về từ bộ nhớ chính. Điều này giúp đảm bảo giá trị của INSTANCE
luôn được cập nhật và giống nhau đối với tất cả luồng thực thi. Điều này có nghĩa là những thay đổi do một luồng đối với INSTANCE
hiển thị ngay lập tức với tất cả các luồng khác, và bạn sẽ không gặp phải một tình huống nào đó, giả sử hai luồng cập nhật cùng một thực thể trong bộ nhớ đệm, điều này sẽ gây ra vấn đề.
@Volatile
private var INSTANCE: SleepDatabase? = null
- Bên dưới
INSTANCE
, vẫn nằm trong đối tượngcompanion
, hãy xác định một phương thứcgetInstance()
có thông sốContext
mà trình tạo cơ sở dữ liệu sẽ cần. Trả về một loạiSleepDatabase
. Bạn sẽ thấy lỗi vìgetInstance()
chưa trả về giá trị nào.
fun getInstance(context: Context): SleepDatabase {}
- Bên trong
getInstance()
, hãy thêm một khốisynchronized{}
. Chuyển vàothis
để có thể truy cập vào ngữ cảnh.
Nhiều chuỗi có khả năng yêu cầu một thực thể của cơ sở dữ liệu cùng lúc, dẫn đến hai cơ sở dữ liệu thay vì một. Sự cố này không có khả năng xảy ra trong ứng dụng mẫu này nhưng có thể xảy ra đối với ứng dụng phức tạp hơn. Nếu bạn gói mã để đưa cơ sở dữ liệu vàosynchronized
, thì tức là chỉ một luồng thực thi mỗi lúc có thể nhập khối mã này, điều này giúp đảm bảo cơ sở dữ liệu chỉ được khởi tạo một lần.
synchronized(this) {}
- Bên trong khối đã đồng bộ hóa, hãy sao chép giá trị hiện tại của
INSTANCE
vào biến cục bộinstance
. Điều này là để tận dụng tính năng truyền thông minh, vốn chỉ có sẵn cho các biến cục bộ.
var instance = INSTANCE
- Bên trong khối
synchronized
,return instance
ở cuối khốisynchronized
. Bỏ qua lỗi về loại trả lại không khớp; bạn sẽ không bao giờ trả lại null sau khi hoàn tất.
return instance
- Phía trên câu lệnh
return
, hãy thêm một câu lệnhif
để kiểm tra xeminstance
có rỗng hay không, tức là chưa có cơ sở dữ liệu.
if (instance == null) {}
- Nếu
instance
lànull
, hãy dùng trình tạo cơ sở dữ liệu để lấy cơ sở dữ liệu. Trong phần nội dung của câu lệnhif
, hãy gọiRoom.databaseBuilder
và cung cấp ngữ cảnh mà bạn đã chuyển vào, lớp cơ sở dữ liệu và tên cho cơ sở dữ liệu,sleep_history_database
. Để xóa lỗi này, bạn phải thêm một chiến lược di chuyển vàbuild()
trong các bước sau.
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database")
- Thêm chiến lược di chuyển cần có vào hàm tạo. Dùng
.fallbackToDestructiveMigration()
.
Thông thường, bạn sẽ phải cung cấp đối tượng di chuyển cho một chiến lược di chuyển khi giản đồ này thay đổi. Đối tượng di chuyển là một đối tượng xác định cách bạn lấy tất cả các hàng có giản đồ cũ và chuyển đổi chúng thành các hàng trong giản đồ mới để không bị mất dữ liệu. Di chuyển nằm ngoài phạm vi của lớp học lập trình này. Giải pháp đơn giản là huỷ bỏ và tạo lại cơ sở dữ liệu, tức là dữ liệu sẽ bị mất.
.fallbackToDestructiveMigration()
- Cuối cùng, hãy gọi
.build()
.
.build()
- Chỉ định
INSTANCE = instance
là bước cuối cùng trong câu lệnhif
.
INSTANCE = instance
- Mã hoàn thiện của bạn sẽ có dạng như sau:
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {
abstract val sleepDatabaseDao: SleepDatabaseDao
companion object {
@Volatile
private var INSTANCE: SleepDatabase? = null
fun getInstance(context: Context): SleepDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}
- Tạo và chạy mã.
Bây giờ, bạn đã có tất cả các khối xây dựng để làm việc với cơ sở dữ liệu Room
. Mã này sẽ biên dịch và chạy, nhưng bạn không có cách nào để biết mã có thực sự hoạt động hay không. Vì vậy, đây là thời điểm thích hợp để thêm một số thử nghiệm cơ bản.
Bước 2: Kiểm tra SleepDatabase
Trong bước này, bạn chạy các thử nghiệm được cung cấp để xác minh rằng cơ sở dữ liệu của bạn có hoạt động. Điều này giúp đảm bảo rằng cơ sở dữ liệu hoạt động trước khi bạn tạo. Các thử nghiệm được cung cấp là cơ bản. Đối với ứng dụng chính thức, bạn sẽ thực hiện tất cả các hàm và truy vấn trong tất cả DAO.
Ứng dụng khởi động chứa thư mục androidTest. Thư mục androidTest này chứa các thử nghiệm đơn vị liên quan đến khả năng đo lường Android. Đây là một cách thú vị để nói rằng các thử nghiệm này cần có khung Android, vì vậy, bạn cần chạy các thử nghiệm trên thiết bị thực hoặc ảo. Tất nhiên, bạn cũng có thể tạo và chạy các thử nghiệm đơn vị thuần túy không liên quan đến khung Android.
- Trong Android Studio, trong thư mục androidTest, hãy mở tệp SleepDatabaseTest.
- Để hủy nhận xét mã, hãy chọn tất cả mã nhận xét và nhấn phím tắt
Cmd+/
hoặcControl+/
. - Hãy xem tệp.
Dưới đây là thông tin nhanh về mã thử nghiệm, bởi vì mã này là một đoạn mã khác mà bạn có thể sử dụng lại:
SleepDabaseTest
là lớp học thử nghiệm.- Chú thích
@RunWith
sẽ xác định người chạy thử nghiệm, là chương trình được thiết lập và thực thi các thử nghiệm. - Trong quá trình thiết lập, hàm được chú thích bằng
@Before
sẽ được thực thi và tạo mộtSleepDatabase
trong bộ nhớ vớiSleepDatabaseDao
. "In-bộ nhớ" có nghĩa là cơ sở dữ liệu này không được lưu trên hệ thống tệp và sẽ bị xoá sau khi thử nghiệm chạy. - Ngoài ra, khi xây dựng cơ sở dữ liệu trong bộ nhớ, mã gọi một phương thức kiểm tra khác,
allowMainThreadQueries
. Theo mặc định, bạn sẽ gặp lỗi nếu cố gắng chạy truy vấn trên chuỗi chính. Phương pháp này cho phép bạn chạy thử nghiệm trên luồng chính. Bạn chỉ nên chạy thử nghiệm này trong quá trình thử nghiệm. - Trong phương thức thử nghiệm được chú thích bằng
@Test
, bạn tạo, chèn và truy xuấtSleepNight
, đồng thời xác nhận rằng các thuộc tính này giống nhau. Nếu có lỗi xảy ra, hãy gửi một ngoại lệ. Trong một thử nghiệm thực tế, bạn sẽ có nhiều phương thức@Test
. - Khi kiểm tra xong, hàm được chú thích bằng
@After
sẽ thực thi để đóng cơ sở dữ liệu.
- Nhấp chuột phải vào tệp thử nghiệm trong ngăn Project rồi chọn Run \39;SleepDatabaseTest#39;.
- Sau khi thử nghiệm chạy xong, hãy xác minh trong ngăn SleepDatabaseTest rằng tất cả các thử nghiệm đã vượt qua.
Vì tất cả các thử nghiệm đã vượt qua, giờ đây bạn biết một số điều:
- Cơ sở dữ liệu được tạo chính xác.
- Bạn có thể chèn một
SleepNight
vào cơ sở dữ liệu. - Bạn có thể khôi phục
SleepNight
. SleepNight
có giá trị chính xác cho chất lượng.
Dự án Android Studio: TrackMySleepqualityRoomAndTest
Khi thử nghiệm cơ sở dữ liệu, bạn cần thực hiện tất cả các phương thức được xác định trong DAO. Để hoàn tất thử nghiệm, hãy thêm và thực thi thử nghiệm để thực hiện các phương thức DAO khác.
- Khai báo các bảng dưới dạng lớp dữ liệu được chú giải bằng
@Entity
. Khai báo các thuộc tính được chú giải bằng@ColumnInfo
dưới dạng cột trong bảng. - Khai báo một đối tượng truy cập dữ liệu (DAO) làm giao diện, kèm theo chú giải bằng
@Dao
. DAO ánh xạ các hàm Kotlin đến các truy vấn cơ sở dữ liệu. - Sử dụng chú giải để xác định các hàm
@Insert
,@Delete
và@Update
. - Sử dụng chú giải
@Query
có chuỗi truy vấn SQLite làm tham số cho mọi truy vấn khác. - Tạo một lớp trừu tượng có hàm
getInstance()
trả về cơ sở dữ liệu. - Sử dụng các thử nghiệm đo lường để kiểm tra xem cơ sở dữ liệu và DAO của bạn có đang hoạt động như mong đợi hay không. Bạn có thể sử dụng các thử nghiệm được cung cấp dưới dạng mẫu.
Khóa học từ Udacity:
Tài liệu dành cho nhà phát triển Android:
RoomDatabase
Database
(chú thích)- Bạn có thể sử dụng cụm từ tìm kiếm thô bằng
Room
Roomdatabase.Builder
- Đào tạo Thử nghiệm
- Lớp
SQLiteDatabase
Dao
- Thư viện lưu trữ
Room
của
Tài liệu và bài viết khác:
Phần này liệt kê các bài tập về nhà có thể được giao cho học viên đang làm việc qua lớp học lập trình này trong khóa học do người hướng dẫn tổ chức. Người hướng dẫn có thể làm những việc sau:
- Giao bài tập về nhà nếu được yêu cầu.
- Trao đổi với học viên cách nộp bài tập về nhà.
- Chấm điểm bài tập về nhà.
Người hướng dẫn có thể sử dụng những đề xuất này ít hay nhiều tùy ý. Do đó, họ có thể thoải mái giao bất kỳ bài tập về nhà nào khác mà họ cảm thấy phù hợp.
Nếu bạn đang tự mình làm việc qua lớp học lập trình này, hãy thoải mái sử dụng các bài tập về nhà này để kiểm tra kiến thức của bạn.
Trả lời những câu hỏi này
Câu hỏi 1
Làm cách nào để cho biết rằng một lớp đại diện cho một thực thể lưu trữ trong cơ sở dữ liệu của Room
?
- Mở rộng
DatabaseEntity
trong lớp. - Chú giải lớp này bằng
@Entity
. - Chú giải lớp này bằng
@Database
. - Mở rộng
RoomEntity
của lớp này rồi chú giải lớp này bằng@Room
.
Câu hỏi 2
DAO (đối tượng truy cập dữ liệu) là giao diện mà Room
sử dụng để ánh xạ các hàm Kotlin với các truy vấn cơ sở dữ liệu.
Làm cách nào để cho biết rằng một giao diện đại diện cho DAO cho cơ sở dữ liệu? Room
- Mở rộng
RoomDAO
trong giao diện. - Mở rộng
EntityDao
trong giao diện, sau đó triển khai phương thứcDaoConnection()
. - Chú giải giao diện này bằng
@Dao
. - Chú giải giao diện này bằng
@RoomConnection
.
Câu hỏi 3
Câu nào sau đây về cơ sở dữ liệu Room
là chính xác? Hãy chọn tất cả phương án phù hợp.
- Bạn có thể xác định bảng cho cơ sở dữ liệu
Room
dưới dạng lớp dữ liệu có chú thích. - Nếu bạn trả về
LiveData
từ một truy vấn, thìRoom
sẽ cập nhậtLiveData
cho bạn nếuLiveData
thay đổi. - Mỗi cơ sở dữ liệu
Room
phải có một và chỉ có một DAO. - Để xác định một lớp là cơ sở dữ liệu của
Room
, hãy đặt lớp đó là lớp con củaRoomDatabase
và chú thích lớp đó bằng@Database
.
Câu hỏi 4
Bạn có thể sử dụng chú giải nào sau đây trong giao diện @Dao
? Hãy chọn tất cả phương án phù hợp.
@Get
@Update
@Insert
@Query
Câu hỏi 5
Làm thế nào để xác minh rằng cơ sở dữ liệu của bạn đang hoạt động? Hãy chọn mọi câu phù hợp.
- Viết các thử nghiệm đo lường.
- Tiếp tục viết và chạy ứng dụng cho đến khi ứng dụng hiển thị dữ liệu.
- Thay thế các lệnh gọi đến phương thức trong giao diện DAO bằng cách gọi các phương thức tương đương trong lớp
Entity
. - Chạy hàm
verifyDatabase()
do thư việnRoom
cung cấp.
Bắt đầu bài học tiếp theo:
Để biết đường liên kết đến các lớp học lập trình khác trong khóa học này, hãy xem trang đích của các lớp học lập trình cơ bản về Android Kotlin.