Lớp học lập trình về Android Sleep API

1. Giới thiệu

Sản phẩm bạn sẽ tạo ra

Trong lớp học lập trình này, bạn sẽ xây dựng một ứng dụng Android để phát hiện thời gian ngủ của người dùng. Ứng dụng này sẽ:

  • Yêu cầu cấp quyền
  • Đăng ký Android Sleep API
  • Truy xuất sự kiện API và cho thấy trên giao diện người dùng
  • Huỷ đăng ký khi không còn cần thiết nữa

Bạn cần có

  • Một phiên bản Android Studio gần đây có Android Build Tools (Công cụ xây dựng Android) phiên bản 21 trở lên
  • Một thiết bị chạy Android 10 (cấp độ API 29) trở lên

2. Thiết lập

Nhân bản kho lưu trữ dự án ban đầu

Để bạn có thể bắt đầu nhanh chóng, chúng tôi đã chuẩn bị một dự án khởi động để bạn tiếp tục xây dựng ứng dụng trên đó. Kiểm tra xem bạn đã cài đặt git hay chưa bằng cách gõ git --version vào dòng lệnh/cửa sổ dòng lệnh. Nếu chưa, bạn hãy làm theo hướng dẫn này để cài đặt. Sau đó, bạn chỉ cần chạy lệnh sau để nhân bản dự án.

 git clone https://github.com/android/codelab-android-sleep/

Nhập dự án

Khởi động Android Studio, chọn "Open an existing Android Studio project" ("Mở một dự án Android Studio hiện có") trên màn hình Welcome (Chào mừng) rồi mở thư mục dự án này.

Sau khi tải dự án, có thể bạn sẽ nhìn thấy cảnh báo cho biết Git không theo dõi tất cả các thay đổi cục bộ của bạn. Bạn có thể nhấp vào "Ignore" (Bỏ qua) hoặc "X" ở góc trên bên phải. (Bạn sẽ không đẩy thay đổi nào ngược trở lại kho lưu trữ Git.)

Ở góc trên bên trái cửa sổ dự án, bạn sẽ thấy như sau nếu đang ở chế độ xem Android. (Nếu đang ở chế độ xem Project (Dự án), bạn cần phải mở rộng dự án để thấy được như này.)

1401a11c10711a60.png

Có hai biểu tượng thư mục (startcomplete). Mỗi thư mục này được gọi là một "mô-đun".

Hãy lưu ý rằng Android Studio có thể mất vài giây để biên dịch dự án ở chế độ nền trong lần đầu tiên. Trong khoảng thời gian này, bạn sẽ thấy một vòng quay trong thanh trạng thái ở phía dưới Android Studio:

4bc64eb3b99eb0ae.png

Bạn nên đợi quá trình này hoàn tất trước khi chỉnh sửa mã nguồn. Quá trình này cho phép Android Studio chuẩn bị tất cả thành phần cần thiết.

Ngoài ra, nếu bạn thấy lời nhắc "Reload for language changes to take effect?" (Tải lại để áp dụng các thay đổi về ngôn ngữ?") hoặc tương tự, hãy chọn "Yes" ("Có").

Tìm hiểu dự án ban đầu

Bạn đã hoàn tất việc thiết lập dự án và sẵn sàng thêm tính năng nhận dạng hoạt động. Chúng ta sẽ dùng mô-đun start làm điểm khởi đầu cho lớp học lập trình này. Nói cách khác, bạn sẽ thêm mã nguồn trong mỗi bước vào start.

Mô-đun complete có thể được dùng để kiểm tra công việc của bạn hoặc dùng để tham khảo nếu bạn gặp vấn đề nào đó.

Tổng quan về các thành phần chính:

  • MainActivity.kt: Kết xuất màn hình chính của ứng dụng khi người dùng khởi chạy ứng dụng.
  • SleepReceiver.kt: Trích xuất các sự kiện ngủ qua API và lưu trữ các sự kiện đó vào cơ sở dữ liệu.
  • BootReceiver.kt: Đăng ký lại Sleep API khi hoàn tất quá trình khởi động thiết bị để tiếp tục nghe các sự kiện Sleep API.

Chạy dự án ban đầu

Giờ hãy chạy ứng dụng.

  1. Kết nối thiết bị Android với máy tính.
  2. Trong thanh công cụ, hãy chọn cấu hình start trên bộ chọn thả xuống, chọn thiết bị của bạn, sau đó nhấp vào nút hình tam giác màu xanh lục (Run (Chạy)) bên cạnh:

177045a302bf57d8.png

Trên thiết bị, bạn sẽ thấy ứng dụng thể hiện như sau:

30efe28b9757e1e7.png

311c83ca64556d94.png

Chúng ta vẫn chưa thực sự thêm mã nguồn nào để theo dõi hoạt động ngủ. Chúng ta sẽ thực hiện việc này trong các phần sau.

Trong phần tiếp theo, chúng ta sẽ xem xét các thư viện và quyền cần thiết.

3. Xem xét thư viện và thêm quyền cho ứng dụng

Xem xét build.gradle và AndroidManifest.xml

Để sử dụng Sleep API trong ứng dụng, bạn phải khai báo phần phụ thuộc cho Google Location and Activity Recognition API (API Nhận dạng vị trí và hoạt động của Google), đồng thời chỉ định quyền cho ứng dụng com.google.android.gms.permission.ACTIVITY_RECOGNITION trong tệp kê khai ứng dụng.

  1. Tìm chuỗi TODO: Review play services library required for activity recognition (CẦN LÀM: Xem xét thư viện Play cần thiết để nhận dạng hoạt động) trong tệp build.gradle của mô-đun start. Bạn không cần làm gì trong bước này. Chỉ cần kiểm tra phần phụ thuộc đã khai báo mà chúng ta cần đến. Phần khai báo sẽ có dạng như sau:
    // TODO: Review play services library required for activity recognition.
    implementation 'com.google.android.gms:play-services-location:18.0.0'
  1. Trong mô-đun start, hãy tìm chuỗi TODO: Add activity recognition and boot complete permissions (CẦN LÀM: Thêm quyền nhận dạng hoạt động và hoàn tất khởi động) trong AndroidManifest.xml rồi thêm mã nguồn sau vào phần tử <manifest>.
<!-- TODO: Add activity recognition and receive boot complete permissions. -->
<!-- Required for 29+. -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Mã nguồn của bạn bây giờ sẽ trông như sau:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.example.sleepcodelab">
...
<!-- TODO: Add activity recognition and receive boot complete permissions. -->
<!-- Required for 29+. -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  ...
</manifest>

Như đã thấy trong phần chú thích, bạn cần thêm quyền khi bắt đầu chạy cho API phiên bản 29.

Vậy là xong! Ứng dụng của bạn giờ đây có thể hỗ trợ tính năng nhận dạng hoạt động ngủ. Bạn chỉ cần thêm mã nguồn ở trên để sử dụng tính năng này.

Xem xét kết quả kiểm tra quyền Nhận dạng hoạt động

Chúng ta cần kiểm tra và yêu cầu cấp quyền khi bắt đầu chạy nếu cần thiết:

  • Trong MainActivity.kt, chúng ta sẽ kiểm tra quyền nhận dạng hoạt động.
  • Nếu các quyền này chưa được cấp phép, chúng ta sẽ gọi displayPermissionSettingsSnackBar(). Thanh thông báo nhanh này sẽ giải thích các nhu cầu cấp quyền và cho phép người dùng phê duyệt quyền đó trong phần cài đặt hệ thống.

Trong mô-đun start, hãy tìm chuỗi TODO: Review Activity Recognition permission check (CẦN LÀM: Xem xét kết quả kiểm tra quyền Nhận dạng hoạt động) trong MainActivity.kt. Bạn sẽ thấy đoạn mã nguồn dưới đây.

Lưu ý: bạn không cần làm gì trong bước này.

// TODO: Review Activity Recognition permission checking.
private fun activityRecognitionPermissionApproved(): Boolean {
   return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(
           this,
           Manifest.permission.ACTIVITY_RECOGNITION
   );
}

Bật/tắt tính năng Sleep tracking (Theo dõi giấc ngủ)

Trong mô-đun start, hãy tìm chuỗi TODO: Enable/Disable Sleep tracking and ask for permissions if needed (CẦN LÀM: Bật/tắt tính năng Theo dõi giấc ngủ và yêu cầu cấp quyền nếu cần) trong MainActivity.kt. Thay thế phương thức onClickRequestSleepData() bằng mã nguồn sau.

// TODO: Enable/Disable sleep tracking and ask for permissions if needed.
fun onClickRequestSleepData(view: View) {
   if (activityRecognitionPermissionApproved()) {
       if (subscribedToSleepData) {
           unsubscribeToSleepSegmentUpdates(applicationContext, sleepPendingIntent)
       } else {
           subscribeToSleepSegmentUpdates(applicationContext, sleepPendingIntent)
       }
   } else {
       requestPermissionLauncher.launch(permission.ACTIVITY_RECOGNITION)
   }
}

Nếu quyền Nhận dạng hoạt động được phê duyệt và nếu người dùng đăng ký dữ liệu giấc ngủ, chúng ta sẽ đăng ký nhận thông tin cập nhật về giấc ngủ. Nếu không, chúng ta sẽ huỷ đăng ký.

Trong trường hợp quyền này không được phê duyệt, chúng ta sẽ gửi cho người dùng hoạt động màn hình chờ để giải thích lý do chúng ta cần quyền này cũng như cho phép người dùng bật quyền đó.

4. Đăng ký nhận thông tin cập nhật của Sleep API

Tạo một PendingIntent

Trong mô-đun start, hãy tìm chuỗi TODO: Create a PendingIntent for Sleep API events (CẦN LÀM: Tạo một PendingIntent cho sự kiện Sleep API) trong MainActivity.kt. Dán đoạn mã sau.

// TODO: Create a PendingIntent for Sleep API events
sleepPendingIntent =
   SleepReceiver.createSleepReceiverPendingIntent(context = applicationContext)

Bây giờ, chúng ta đã có cách để nhận thông tin cập nhật khi có dữ liệu của Sleep API.

Yêu cầu cấp thông tin cập nhật của Sleep API

Trong mô-đun start, hãy tìm chuỗi TODO: Request Sleep API updates (CẦN LÀM: Yêu cầu cấp thông tin cập nhật của Sleep API) trong MainActivity.kt. Dán đoạn mã sau.

// TODO: Request Sleep API updates
val task = ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
   pendingIntent,
   // Registers for both SleepSegmentEvent and SleepClassifyEvent data.
   SleepSegmentRequest.getDefaultSleepSegmentRequest()
)

task.addOnSuccessListener {
   mainViewModel.updateSubscribedToSleepData(true)
   Log.d(TAG, "Successfully subscribed to sleep data.")
}
task.addOnFailureListener { exception ->
   Log.d(TAG, "Exception when subscribing to sleep data: $exception")
}

Sau khi đăng ký thành công để nhận thông tin cập nhật của Sleep API, ứng dụng của bạn sẽ nhận được thông báo phát hiện giấc ngủ trong PendingIntent đã đăng ký.

Đăng ký lại sau khi khởi động xong

Trong mô-đun start, hãy tìm chuỗi TODO: Request Sleep API upon boot complete (CẦN LÀM: Yêu cầu Sleep API khi khởi động xong) trong receiver/BootReceiver.kt. Dán đoạn mã sau.

// TODO: Request Sleep API upon boot complete
val subscribedToSleepData = repository.subscribedToSleepDataFlow.first()
if (subscribedToSleepData) {
   subscribeToSleepSegmentUpdates(
       context = context,
       pendingIntent = SleepReceiver.createSleepReceiverPendingIntent(context)
   )
}

Mã nguồn này cho phép ứng dụng tiếp tục nhận thông tin cập nhật của Sleep API sau khi thiết bị khởi động lại.

5. Xử lý sự kiện

Khi thuật toán phân loại thời gian ngủ hoặc phát hiện thời gian ngủ diễn ra, ứng dụng của bạn sẽ nhận một lệnh gọi lại Intent (Ý định). Bạn có thể trích xuất danh sách đối tượng SleepSegmentEvent hoặc SleepClassifyEvent.

Hãy thêm mã nguồn sau đây để xử lý các sự kiện đó.

Trong mô-đun start, hãy tìm chuỗi TODO: Extract sleep information from PendingIntent (CẦN LÀM: Trích xuất thông tin về giấc ngủ qua PendingIntent) trong receiver/SleepReceiver.kt. Sau đó, hãy thêm mã sau vào phần chú thích.

// TODO: Extract sleep information from PendingIntent.
if (SleepSegmentEvent.hasEvents(intent)) {
   val sleepSegmentEvents: List<SleepSegmentEvent> =
       SleepSegmentEvent.extractEvents(intent)
   addSleepSegmentEventsToDatabase(repository, sleepSegmentEvents)
} else if (SleepClassifyEvent.hasEvents(intent)) {
   val sleepClassifyEvents: List<SleepClassifyEvent> =
       SleepClassifyEvent.extractEvents(intent)
   addSleepClassifyEventsToDatabase(repository, sleepClassifyEvents)
}

Thao tác này sẽ lưu dữ liệu SleepSegmentEvent hoặc SleepClassifyEvent vào cơ sở dữ liệu Room. MainActivity sẽ truy cập thông tin của cơ sở dữ liệu đó thông qua một ViewModel sử dụng LiveData. Để tìm hiểu thêm về cách các lớp này hoạt động cùng nhau, hãy tham khảo Lớp học lập trình về Room có Khung hiển thị (View).

Vậy là xong! Bạn đã hoàn thành ứng dụng! Bạn có thể chạy ứng dụng để xem thành quả của mình.

6. Cài đặt ứng dụng và xem xét mã

Kết nối thiết bị với máy trạm thông qua một dây cáp. Nhấp vào "Run" ("Chạy") trong Android Studio để cài đặt và chạy ứng dụng trên thiết bị. Sau khi cấp quyền Nhận dạng hoạt động và nhấn vào nút SUBSCRIBE TO SLEEP DATA (ĐĂNG KÝ NHẬN DỮ LIỆU GIẤC NGỦ), SleepClassifyEvent đầu tiên sẽ xuất hiện sau khoảng 10 phút. SleepSegmentEvent sẽ xuất hiện trong vòng một ngày.

Hãy đọc toàn bộ mã nguồn để xem lại những gì bạn đã làm cũng như để hiểu rõ hơn về cách thức hoạt động của những mã nguồn này.

Xem xét mã nguồn (không bắt buộc)

Việc xem xét những mã nguồn sau đây là không bắt buộc. Những mã nguồn này sẽ đưa ra thông tin chi tiết về mối liên kết dữ liệu giữa Sleep API và các thực thể cơ sở dữ liệu:

  • data/db/SleepClassifyEventEntity.kt
  • data/db/SleepSegmentEventEntity.kt

Tài liệu tham khảo