Lớp học lập trình này nằm trong khoá học Kotlin nâng cao cho Android. Bạn sẽ nhận được nhiều giá trị nhất qua khoá học này nếu thực hiện các lớp học lập trình theo trình tự, nhưng đó không phải là yêu cầu bắt buộc. Tất cả các lớp học lập trình của khoá học đều được liệt kê trên trang đích của lớp học lập trình Kiến thức nâng cao về cách tạo ứng dụng Android bằng Kotlin.
Giới thiệu
Thông báo là những thông điệp hiển thị cho người dùng bên ngoài giao diện người dùng của ứng dụng. Thông báo sẽ xuất hiện ở đầu màn hình nếu thiết bị đang mở khoá hoặc trên màn hình khoá khi thiết bị đang khoá (tuỳ thuộc vào chế độ cài đặt bảo mật).
Một thông báo thông thường bao gồm tiêu đề, nội dung mô tả và biểu tượng. Thông báo cũng có thể có các thao tác có thể nhấp, câu trả lời nhanh, nội dung có thể mở rộng và hình ảnh.
Thông báo có thể cung cấp nội dung kịp thời và có thể có các nút để cho phép người dùng thực hiện các thao tác nhanh, chẳng hạn như gửi câu trả lời hoặc tạm ẩn chuông báo. Khi nhấp vào một thông báo, người dùng sẽ được chuyển đến một khung hiển thị trong ứng dụng của bạn có liên quan đến nội dung thông báo.
Thông báo là một cách hữu ích để nhắc người dùng về một việc quan trọng, cho họ biết có điều gì đó đã xảy ra hoặc truyền đạt thông tin quan trọng mà họ cần ngay lập tức khi ứng dụng của bạn chạy ở chế độ nền. Chỉ sử dụng thông báo khi cần thiết. Việc này không chỉ thể hiện sự tôn trọng người dùng mà còn giúp thông báo của ứng dụng có nhiều khả năng nhận được sự chú ý xứng đáng.
Trong lớp học lập trình này, bạn sẽ tìm hiểu cách tạo và sử dụng thông báo trong một ứng dụng Android.
Kiến thức bạn cần có
Bạn cần thông thạo:
- Cách tạo ứng dụng Android trong Kotlin. Đặc biệt là làm việc với SDK Android.
- Cách thiết kế cấu trúc ứng dụng bằng cách sử dụng các Thành phần cấu trúc và mối liên kết dữ liệu.
- Có kiến thức cơ bản về BroadcastReceiver
- Hiểu biết cơ bản về AlarmManager
Kiến thức bạn sẽ học được
- Cách tạo, tạo kiểu và gửi thông báo.
- Cách huỷ thông báo.
- Cách tạo kênh thông báo.
- Cách thêm thao tác nhanh vào thông báo.
- Cách hiển thị huy hiệu thông báo trên biểu tượng ứng dụng.
Bạn sẽ thực hiện
- Thêm thông báo vào ứng dụng khởi động.
- Huỷ thông báo mà bạn đã gửi trước đó.
- Tạo các kênh cho nhiều loại thông báo.
- Tuỳ chỉnh thông báo trong ứng dụng khởi động.
- Thêm Thao tác nhanh để thông báo của bạn mang tính tương tác.
- Tắt huy hiệu thông báo.
Luộc trứng là một việc đơn giản, nhưng có thể trở thành một việc khó khăn nếu bạn không theo dõi thời gian. Trong lớp học lập trình này, bạn sẽ làm việc trên một ứng dụng hẹn giờ luộc trứng và hoàn thiện ứng dụng này, giống như những quả trứng trong tương lai của bạn. Bạn sẽ bắt đầu với một ứng dụng hẹn giờ nấu trứng hoạt động, cho phép người dùng đặt các chế độ cài đặt thời gian nấu khác nhau cho các kiểu trứng khác nhau. Bộ hẹn giờ sẽ đếm ngược từ khoảng thời gian đã chọn và hiển thị một thông báo ngắn khi trứng chín.
Điều này có vẻ hiệu quả, nhưng chưa hoàn hảo và không thực sự thân thiện với người dùng. Trước tiên, thông báo toast chỉ xuất hiện trong một khoảng thời gian ngắn, do đó rất dễ bị bỏ lỡ. Ngoài ra, nếu ứng dụng không ở nền trước hoặc thiết bị bị khoá, thì sẽ không có chỉ báo trực quan nào cho trạng thái của bộ hẹn giờ sau khi thông báo toast biến mất.
Tốt nhất là đồng hồ hẹn giờ nên dùng thông báo để cho người dùng biết khi hết thời gian. Người dùng thực sự cần biết trứng đã sẵn sàng ngay lập tức, nếu không trứng sẽ bị nấu quá chín! Thông báo là thông tin trực quan, có thể bao gồm âm thanh và có thể khiến thiết bị rung – tất cả những cách này đều giúp thu hút sự chú ý của người dùng! Bằng cách này, bạn có thể chế biến những quả trứng hoàn hảo và người dùng sẽ hài lòng, no bụng.
Để lấy ứng dụng mẫu, bạn có thể:
Sao chép kho lưu trữ trên GitHub và chuyển sang nhánh starter.
$ git clone https://github.com/googlecodelabs/android-kotlin-notifications
Ngoài ra, bạn có thể tải kho lưu trữ xuống dưới dạng tệp Zip, giải nén rồi mở trong Android Studio.
- Mở và chạy ứng dụng trong Android Studio.
Bạn sẽ thấy hình ảnh quả trứng và một trình đơn thả xuống có danh sách các khoảng thời gian được xác định trước để nấu trứng. Nhấp vào biểu tượng tam giác để mở trình đơn thả xuống Luộc lòng đào. Lựa chọn đầu tiên trong danh sách được đưa ra cho mục đích kiểm thử và chỉ đặt báo thức trong 10 giây. Bên cạnh danh sách là một nút chuyển để bắt đầu hẹn giờ. Bạn có thể dùng công tắc này để bắt đầu và dừng bộ tính giờ bất cứ lúc nào bạn muốn. Mã khởi đầu có đầy đủ chức năng, tức là bạn có thể thiết lập đồng hồ hẹn giờ và xem đồng hồ đếm ngược đến 0. Sau khi bộ hẹn giờ kết thúc, một thông báo nhanh sẽ xuất hiện, như minh hoạ dưới đây.
- Kiểm tra mã nguồn. Ứng dụng khởi đầu bao gồm một hoạt động duy nhất có tên là
MainActivity
. Có 3 gói con có tên làreceiver
,ui
vàutil
.
- /receiver – Gói
receiver
chứa hai broadcast receiver có tên làAlarmReceiver
vàSnoozeReceiver
.AlarmReceiver
được kích hoạt bởiAlarmManager
để gửi thông báo khi hết thời gian hẹn giờ do người dùng xác định.SnoozeReceiver
xử lý lượt nhấp của người dùng để tạm ngưng thông báo. - /ui – Thư mục này chứa
EggTimerFragment
, là một phần của giao diện người dùng của ứng dụng.EggTimerViewModel
chịu trách nhiệm bắt đầu và huỷ hẹn giờ cũng như các tác vụ khác của ứng dụng liên quan đến vòng đời. - /util – Trong gói này có 2 tệp.
BindingUtils.kt
có các bộ chuyển đổi liên kết để bật tính năng liên kết dữ liệu giữa giao diện người dùng ứng dụng vàViewModel
.NotificationUtils.kt
có các phương thức mở rộng trênNotificationManager
.
Sử dụng thông báo là một cách hiệu quả để thu hút sự chú ý của người dùng đến ứng dụng của bạn. Cho dù ứng dụng của bạn không chạy hay chạy ở nền trước, thông báo sẽ hiển thị một cửa sổ bật lên ở đầu màn hình và có thể bao gồm âm thanh hoặc chế độ rung. Để tạo thông báo, bạn cần sử dụng trình tạo thông báo và cung cấp văn bản tiêu đề, văn bản nội dung và biểu tượng. Sau khi trình tạo có tất cả các trường cần thiết, NotificationManager
(một dịch vụ hệ thống) sẽ giúp bạn hiển thị nội dung này dưới dạng thông báo. NotificationManager
chịu trách nhiệm gửi thông báo, cập nhật nội dung và huỷ thông báo. Trong các bước sau, bạn sẽ thêm các phương thức mở rộng vào NotificationManager
. Bằng cách này, mỗi khi cần sử dụng NotificationManager
, bạn sẽ có thể sử dụng các hàm mở rộng này để đạt được chức năng cần dùng.
Bước 1: Tạo một Thông báo cơ bản
Trong nhiệm vụ này, bạn sẽ tạo một thông báo mới, đặt thông báo cho người dùng và gửi thông báo.
- Mở lớp
NotificationUtils.kt
rồi tìmTODO: Step 1.1
. Bạn sẽ thấy các việc cần làm tương ứng trong lớp học lập trình này và mã ứng dụng. - Kiểm tra hàm
sendNotification()
đã cho. Bạn sẽ mở rộng hàm mở rộng này thànhNotificationManager
để gửi thông báo.
//NotificationUtils.kt
// TODO: Step 1.1 extension function to send messages (GIVEN)
/**
* Builds and delivers a notification.
*
* @param messageBody, notification text.
* @param context, activity context.
*/
fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
- Lấy một phiên bản của trình tạo thông báo, truyền ngữ cảnh ứng dụng và mã kênh. Mã nhận dạng kênh là một giá trị chuỗi cho kênh.
Kênh thông báo là một cách để nhóm các thông báo. Bằng cách nhóm các loại thông báo tương tự với nhau, nhà phát triển và người dùng có thể kiểm soát tất cả thông báo trong kênh. Sau khi tạo, bạn có thể dùng kênh này để gửi bất kỳ số lượng thông báo nào.
//NotificationUtils.kt
// TODO: Step 1.2 get an instance of NotificationCompat.Builder
val builder = NotificationCompat.Builder(
applicationContext,
applicationContext.getString(R.string.egg_notification_channel_id)
)
- Đặt biểu tượng thông báo để biểu thị ứng dụng của bạn, tiêu đề và văn bản nội dung cho thông báo mà bạn muốn gửi cho người dùng. Bạn sẽ thấy nhiều lựa chọn hơn để tuỳ chỉnh thông báo trong lớp học lập trình, nhưng đây là lượng dữ liệu tối thiểu bạn cần đặt để gửi thông báo.
//NotificationUtils.kt
// TODO: Step 1.3 set title, text and icon to builder
.setSmallIcon(R.drawable.cooked_egg)
.setContentTitle(applicationContext.getString(R.string.notification_title))
.setContentText(messageBody)
- Tiếp theo, bạn cần gọi
notify()
bằng một mã nhận dạng duy nhất cho thông báo và bằng đối tượngNotification
từ trình tạo của bạn.
Mã nhận dạng này đại diện cho phiên bản thông báo hiện tại và cần thiết để cập nhật hoặc huỷ thông báo này. Vì ứng dụng của bạn sẽ chỉ có một thông báo đang hoạt động tại một thời điểm nhất định, nên bạn có thể dùng cùng một mã nhận dạng cho tất cả thông báo. Bạn đã được cung cấp một hằng số cho mục đích này, đó là NOTIFICATION_ID
trong NotificationUtils.kt
. Xin lưu ý rằng bạn có thể gọi trực tiếp notify()
vì bạn đang thực hiện lệnh gọi từ một hàm mở rộng trên cùng một lớp.
//NotificationUtils.kt
// TODO: Step 1.4 call notify to send the notification
// Deliver the notification
notify(NOTIFICATION_ID, builder.build())
- Mở
ui/EggTimerViewModel.kt
rồi tìm hàmstartTimer()
. Hàm này tạo một chuông báo với khoảng thời gian đã chọn khi người dùng bật đồng hồ hẹn giờ. - Bạn sẽ kích hoạt một thông báo trong hàm này khi người dùng bắt đầu hẹn giờ. Để gọi hàm
sendNotification()
mà bạn đã triển khai trước đó, bạn cần một thực thể củaNotificationManager
.NotificationManager
là một dịch vụ hệ thống cung cấp tất cả các chức năng được hiển thị cho API thông báo, bao gồm cả hàm tiện ích mà bạn đã thêm. Bất cứ khi nào muốn gửi, huỷ hoặc cập nhật một thông báo, bạn cần yêu cầu một phiên bản củaNotificationManager
từ hệ thống. Gọi hàmsendNotification()|
bằng thông báo và theo ngữ cảnh.
// EggTimerViewModel.kt
// TODO: Step 1.5 get an instance of NotificationManager
// and call sendNotification
val notificationManager = ContextCompat.getSystemService(
app,
NotificationManager::class.java
) as NotificationManager
notificationManager.sendNotification(app.getString(R.string.timer_running), app)
Bạn sắp hoàn tất rồi. Tuy nhiên, nếu chạy ứng dụng ngay bây giờ và đặt bộ tính giờ, bạn sẽ không nhận được thông báo.
- Mở
logcat
rồi tìm"No Channel found"
. Bạn sẽ thấy thông báo lỗi cho biếtegg_channel
không tồn tại. Trong các bước sau, bạn sẽ tìm hiểu thêm về Kênh thông báo và khắc phục vấn đề này.
Bước 2: Kênh thông báo
Kể từ API cấp 26, bạn phải chỉ định kênh cho tất cả thông báo. Nếu nhấn và giữ biểu tượng trình chạy ứng dụng, chọn thông tin ứng dụng rồi nhấn vào thông báo, bạn sẽ thấy danh sách các kênh thông báo được liên kết với ứng dụng. Hiện tại, danh sách này đang trống vì ứng dụng của bạn chưa tạo kênh nào.
Kênh đại diện cho một "loại" thông báo – ví dụ: đồng hồ hẹn giờ luộc trứng có thể gửi thông báo khi trứng chín, đồng thời sử dụng một kênh khác để gửi thông báo hằng ngày nhắc bạn ăn trứng vào bữa sáng. Tất cả thông báo trong một kênh sẽ được nhóm lại với nhau và người dùng có thể định cấu hình chế độ cài đặt thông báo cho toàn bộ kênh. Nhờ đó, người dùng có thể cá nhân hoá chế độ cài đặt thông báo dựa trên loại thông báo mà họ quan tâm. Ví dụ: người dùng có thể tắt thông báo về bữa sáng nhưng vẫn chọn xem thông báo từ bộ hẹn giờ.
Nhà phát triển thiết lập các chế độ cài đặt ban đầu, mức độ quan trọng và hành vi sẽ được áp dụng cho tất cả thông báo trong một kênh. Sau khi bạn thiết lập các chế độ cài đặt ban đầu, người dùng có thể ghi đè các chế độ cài đặt này.
Trong Bước 1.1, bạn đã sử dụng egg_notification_channel_id
làm kênh thông báo. Vì vậy, giờ đây, bạn cần thực sự tạo và tuỳ chỉnh chế độ cài đặt thông báo cũng như hành vi của kênh này.
- Mở
EggTimerFragment.kt
rồi tìm hàmcreateChannel()
. - Truyền mã nhận dạng kênh duy nhất vào hàm khởi tạo của
NotificationChannel
. - Truyền tên kênh thông báo mà người dùng cũng sẽ thấy trên màn hình Cài đặt.
- Truyền mức độ quan trọng cho kênh thông báo làm tham số cuối cùng. Các cấp độ quan trọng sẽ được đề cập ở phần sau trong lớp học lập trình này, vì vậy, hiện tại bạn có thể sử dụng
NotificationManag
er.IMPORTANCE_LOW
. - Trên đối tượng
notificationChannel
, hãy đặtenableLights
thành true. Chế độ cài đặt này sẽ bật đèn khi có thông báo xuất hiện. - Trên đối tượng
notificationChannel
, hãy đặtlightColor
thành màu đỏ để hiển thị đèn đỏ khi một thông báo xuất hiện. - Trên đối tượng
notificationChannel
, hãy đặtenableVibration
thành true để bật chế độ rung. - Trên đối tượng
notificationChannel
, hãy đặt nội dung mô tả kênh thành‘Time for breakf
ast'. - Lấy một thực thể của
NotificationManager
bằng cách gọigetSystemService()
. - Gọi
createNotificationChannel()
trênNotificationManager
và truyền đối tượngnotificationChannel
mà bạn đã tạo ở bước trước.
//EggTimerFragment.kt
private fun createChannel(channelId: String, channelName: String) {
// TODO: Step 1.6 START create a channel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationChannel = NotificationChannel(
channelId,
channelName,
// TODO: Step 2.4 change importance
NotificationManager.IMPORTANCE_LOW
)
// TODO: Step 2.6 disable badges for this channel
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.RED
notificationChannel.enableVibration(true)
notificationChannel.description = "Time for breakfast"
val notificationManager = requireActivity().getSystemService(
NotificationManager::class.java
)
notificationManager.createNotificationChannel(notificationChannel)
}
// TODO: Step 1.6 END create channel
}
- Tiếp theo, để tạo một kênh, bạn cần gọi hàm
createChannel()
mà bạn vừa viết (Bước 1.7). Hàm này nhận 2 tham số là mã nhận dạng kênh và tên kênh. Bạn cần tra cứu mã nhận dạng kênh và tên kênh trong các tài nguyên chuỗi đã có trong dự án của mình.
// EggTimerFragment.kt
// TODO: Step 1.7 call createChannel
createChannel(
getString(R.string.egg_notification_channel_id),
getString(R.string.egg_notification_channel_name)
)
- Bạn cần truyền mã nhận dạng kênh đến trình tạo thông báo. Bạn đã thực hiện việc này trong Bước 1.2. Việc đặt một giá trị không chính xác làm mã nhận dạng kênh sẽ khiến thông báo không gửi được. Mở
NotificationUtils.kt
để xác minh rằng mã nhận dạng kênh mà bạn đã đặt trước đó là chính xác.
// NotificationUtils.kt
val builder = NotificationCompat.Builder(
applicationContext,
// TODO: Step 1.8 verify the notification channel name
applicationContext.getString(R.string.egg_notification_channel_id)
)
- Chạy ứng dụng và bạn sẽ thấy ứng dụng gửi thông báo mỗi khi bạn bắt đầu hẹn giờ.
- Kéo thanh trạng thái xuống và quan sát để thấy tiêu đề, nội dung và biểu tượng thông báo giống như bạn đã đặt ở các bước trước.
- Để xác minh kênh mới tạo, hãy đóng ứng dụng rồi tìm biểu tượng ứng dụng. Nhấn và giữ biểu tượng ứng dụng rồi chọn Thông tin ứng dụng.
- Chọn Thông báo trong danh sách chế độ cài đặt. Bạn sẽ thấy một kênh mới có tên là Egg (Trứng), ngay bên dưới chế độ cài đặt Hiện thông báo.
Khi bạn chạy ứng dụng, thông báo sẽ xuất hiện. Cả bạn (với vai trò là nhà phát triển ứng dụng) và người dùng đều có thể tuỳ chỉnh chế độ cài đặt và hành vi cho tất cả thông báo được gửi trên kênh này. Xin chúc mừng, bạn đã tạo một thông báo!
Bước 3: Thêm thông báo vào ứng dụng
Cho đến nay, điều này cho thấy cách sử dụng cơ bản của API thông báo, nhưng việc gửi thông báo ngay sau khi bắt đầu bộ hẹn giờ không có nhiều ý nghĩa. Người dùng có thể muốn nhận được thông báo khi trứng đã sẵn sàng. Trong phần tiếp theo của lớp học lập trình, bạn sẽ khắc phục vấn đề này và thay đổi thông báo tạm thời thành thông báo.
Bạn đã gửi thông báo và quan sát cách thông báo hiển thị cho người dùng, nhưng đây chỉ là bước đầu tiên để tạo ra những thông báo hiệu quả. Trong bước này, bạn sẽ thay đổi thời điểm gửi thông báo cho phù hợp hơn.
Ứng dụng của bạn dùng AlarmManager
để thiết lập chuông báo. Mã liên quan đến AlarmManager
đã có trong mã khởi đầu và được dùng để hiện thông báo ngắn. AlarmManager
theo dõi lựa chọn thời gian mong muốn và sẽ kích hoạt hàm onReceive()
của AlarmReceiver.kt
khi hết thời gian. Nếu mở AlarmReceiver.kt
và chuyển đến onReceive()
, bạn sẽ thấy thông báo dạng toast xuất hiện mỗi khi bạn thiết lập một bộ hẹn giờ.
- Mở
AlarmReceiver.kt
, một thực thể củaNotificationManager
, rồi gọi hàmsendNotification()
bằng văn bản thông báo và các tham số ngữ cảnh.
// AlarmReceiver.kt
// TODO: Step 1.9 add call to sendNotification
val notificationManager = ContextCompat.getSystemService(
context,
NotificationManager::class.java
) as NotificationManager
notificationManager.sendNotification(
context.getText(R.string.eggs_ready).toString(),
context
)
- Bạn có thể xoá thông báo ngắn vì ứng dụng sẽ gửi thông báo khi hết thời gian hẹn giờ.
// AlarmReceiver.kt
// TODO: Step 1.10 [Optional] remove toast
// Toast.makeText(
// context,
// context.getText(R.string.eggs_ready),
// Toast.LENGTH_SHORT
// ).show()
- Chạy ứng dụng của bạn . Bạn sẽ thấy thông báo mỗi khi bắt đầu và kết thúc bộ hẹn giờ.
Điều này không lý tưởng. Bạn không nên gửi quá nhiều thông báo cho người dùng. Bạn có thể xoá thông báo đầu tiên được gửi khi người dùng bắt đầu hẹn giờ.
- Mở
EggTimerFragment.kt
rồi xoá mã thông báo cho Bước 1.5.
// EggTimeViewModel.kt
// TODO: Step 1.5 get an instance of NotificationManager
// and call sendNotification
// val notificationManager = ContextCompat.getSystemService(
// app,
// NotificationManager::class.java
// ) as NotificationManager
// notificationManager.sendNotification(app.getString(R.string.eggs_ready), app)
- Chạy lại ứng dụng.
- Đặt hẹn giờ, chuyển ứng dụng xuống nền và đợi hết thời gian. Bạn sẽ thấy một thông báo. Đây là một thông báo hữu ích hơn nhiều.
Bước 4: Thêm ý định về nội dung
- Chạy lại ứng dụng nếu ứng dụng chưa chạy.
- Nhấp vào thông báo đó. Không có gì xảy ra cả!
Việc hiển thị thông báo và thông báo cho người dùng là rất tốt, nhưng khi người dùng nhấp vào một thông báo, họ mong muốn quay lại ứng dụng tương ứng. Trong phần này của lớp học lập trình, bạn sẽ thêm một intent vào thông báo để đưa người dùng quay lại màn hình hẹn giờ.
Intent
là một đối tượng nhắn tin mà bạn có thể dùng để yêu cầu một thao tác từ một thành phần ứng dụng khác. Bạn có thể dùng ý định để bắt đầu một hoạt động, dịch vụ hoặc gửi một thông báo truyền tin. Trong trường hợp này, bạn dùng ý định này để yêu cầu hệ thống mở MainActivity
khi người dùng nhấn vào thông báo. Vì ứng dụng của bạn chỉ có một khung hiển thị duy nhất, nên bạn không có nhiều lựa chọn ở đây. Tuy nhiên, trong một ứng dụng lớn hơn, thông báo sẽ tạo ra trải nghiệm liền mạch bằng cách đưa người dùng đến một màn hình phù hợp khi họ tương tác với thông báo.
- Mở
NotificationUtils.kt
rồi tìm hàm tiện íchsendNotification()
. - Tạo một
Intent
bằngapplicationContext
và hoạt động sẽ được khởi chạy,MainActivity::class.java
.
// NotificationUtils.kt
fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
// Create the content intent for the notification, which launches
// this activity
// TODO: Step 1.11 create intent
val contentIntent = Intent(applicationContext, MainActivity::class.java)
Bạn đã tạo ý định, nhưng thông báo xuất hiện bên ngoài ứng dụng của bạn. Để một ý định hoạt động bên ngoài ứng dụng, bạn cần tạo một PendingIntent
mới.
PendingIntent
cấp quyền cho một ứng dụng khác hoặc hệ thống thực hiện một thao tác thay cho ứng dụng của bạn. Bản thân PendingIntent
chỉ là một mã tham chiếu đến mã thông báo do hệ thống duy trì, mô tả dữ liệu ban đầu dùng để truy xuất mã thông báo đó. Điều này có nghĩa là ngay cả khi quy trình của ứng dụng sở hữu bị xoá, bản thân PendingIntent
vẫn có thể sử dụng được từ các quy trình khác mà ứng dụng đã được cấp. Trong trường hợp này, hệ thống sẽ dùng ý định đang chờ xử lý để mở ứng dụng thay cho bạn, bất kể ứng dụng hẹn giờ có đang chạy hay không.
- Tạo một
PendingIntent
bằngapplicationContext
,NOTIFICATION_ID
,contentIntent
mà bạn đã tạo ở bước trước và cờPendingIntent
. CờPendingIntent
chỉ định lựa chọn tạoPendingIntent
mới hoặc sử dụngPendingIntent
hiện có. Bạn cần đặtPendingIntent.FLAG_UPDATE_CURRENT
làm cờ vì bạn không muốn tạo thông báo mới nếu đã có thông báo. Bằng cách này, bạn sẽ sửa đổiPendingIntent
hiện tại được liên kết với ý định mà bạn đang cung cấp.
// NotificationUtils.kt
// TODO: Step 1.12 create PendingIntent
val contentPendingIntent = PendingIntent.getActivity(
applicationContext,
NOTIFICATION_ID,
contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
- Truyền
PendingIntent
đến thông báo của bạn. Bạn có thể thực hiện việc này bằng cách gọisetContentIntent()
trênNotificationBuilder
. Giờ đây, khi bạn nhấp vào thông báo,PendingIntent
sẽ được kích hoạt, mởMainActivity
. - Bạn cũng nên đặt
setAutoCancel()
thànhtrue
để khi người dùng nhấn vào thông báo, thông báo sẽ tự đóng khi đưa họ đến ứng dụng.
// NotificationUtils.kt
// TODO: Step 1.13 set content intent
.setContentIntent(contentPendingIntent)
.setAutoCancel(true)
- Chạy lại ứng dụng.
- Đặt hẹn giờ, chuyển ứng dụng xuống nền và đợi thông báo xuất hiện.
- Sau khi bạn thấy thông báo, hãy nhấp vào thông báo bằng cách kéo thanh trạng thái xuống và quan sát cách ứng dụng được đưa lên nền trước.
Bước 5: Huỷ thông báo
Bạn có một đồng hồ hẹn giờ hoạt động được và có thông báo, nhưng có một vấn đề nhỏ. Nếu bạn đặt bộ hẹn giờ, nhận được thông báo rồi đặt lại bộ hẹn giờ, thì thông báo trước đó vẫn sẽ xuất hiện trên thanh trạng thái trong khi bộ hẹn giờ mới đang chạy. Điều này có thể gây nhầm lẫn cho người dùng nếu ứng dụng đang chạy trong nền và có thể dẫn đến trứng chưa chín.
Để khắc phục vấn đề này, bạn cần xoá thông báo trước đó khi bắt đầu một bộ hẹn giờ mới. Bắt đầu bằng cách tạo một hàm mở rộng khác trong NotificationUtils.kt
. NotificationManager
có một API để huỷ tất cả thông báo đang hoạt động, được gọi là cancelAll
()
.
- Mở
NotificationsUtil.kt
. - Thêm một hàm mở rộng trên
NotificationManager
gọicancelAll()
.
// NotificationUtils.kt
// TODO: Step 1.14 Cancel all notifications
/**
* Cancels all notifications.
*
*/
fun NotificationManager.cancelNotifications() {
cancelAll()
}
- Mở
EggTimerViewModel.kt
rồi chuyển đến hàmstartTimer()
. - Trong
startTimer()
, hãy lấy một thực thể củaNotificationManager
từ hệ thống và gọicancelNotifications()
.
// EggTimerViewModel.kt
//TODO Step 1.15 call cancel notification
val notificationManager =
ContextCompat.getSystemService(
app,
NotificationManager::class.java
) as NotificationManager
notificationManager.cancelNotifications()
- Chạy ứng dụng rồi bắt đầu đếm thời gian.
- Sau khi bạn thấy thông báo, hãy bắt đầu lại bộ hẹn giờ và quan sát cách ứng dụng của chúng tôi tự động xoá thông báo trước đó khỏi thanh trạng thái.
Khung thông báo cung cấp nhiều lựa chọn tuỳ chỉnh để nhà phát triển thiết lập các thao tác tuỳ chỉnh và tạo kiểu cho thông báo khi cần. Trong nhiệm vụ này, bạn sẽ tìm hiểu cách tuỳ chỉnh thông báo của đồng hồ hẹn giờ.
Bước 1: Tạo kiểu cho thông báo
Việc tạo kiểu cho thông báo theo nhu cầu và nội dung thông báo sẽ giúp thông báo của bạn nổi bật và trông giống như một phần mở rộng của ứng dụng. Khung thông báo có sẵn một số kiểu tích hợp để hỗ trợ, và bạn luôn có thể tạo kiểu riêng.
NotificationCompat
cung cấp các kiểu tích hợp cho:
BigTextStyle
, có thể hiển thị một khối văn bản lớn, chẳng hạn như hiển thị nội dung của email khi được mở rộng.BigPictureStyle
, cho thấy các thông báo ở định dạng lớn, bao gồm cả một tệp đính kèm hình ảnh lớn.InboxStyle
, cho thấy nội dung văn bản theo kiểu trò chuyện.MediaStyle
, cho thấy các nút điều khiển để phát nội dung nghe nhìn.MessagingStyle
, cho thấy các thông báo ở định dạng lớn, bao gồm nhiều tin nhắn giữa một số người bất kỳ.
Bạn có thể tìm thêm thông tin về các kiểu khác trong tài liệu về Tạo thông báo có thể mở rộng. Trong bước này, bạn sẽ sử dụng NotificationCompat.BigPictureStyle
để tạo một thông báo có thể mở rộng, cho thấy hình ảnh quả trứng lớn khi được mở rộng.
- Mở
NotificationUtils.kt
rồi tìm hàmsendNotification()
. - Bắt đầu bằng cách tải một hình ảnh từ
resources
bằng cách sử dụngBitmapFactory
.
// NotificationUtils.kt
// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
applicationContext.resources,
R.drawable.cooked_egg
)
- Tạo một
BigPictureStyle
mới và đặt hình ảnh. - Đặt
bigLargeIcon()
thànhnull
để biểu tượng lớn biến mất khi thông báo được mở rộng.
// NotificationUtils.kt
// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
applicationContext.resources,
R.drawable.cooked_egg
)
val bigPicStyle = NotificationCompat.BigPictureStyle()
.bigPicture(eggImage)
.bigLargeIcon(null)
- Đặt kiểu bằng
setStyle()
thànhbigPicStyle
. - Đặt biểu tượng lớn có
setLargeIcon()
thànheggImage
, để hình ảnh sẽ xuất hiện dưới dạng biểu tượng nhỏ hơn khi thông báo bị thu gọn.
// NotificationUtils.kt
// TODO: Step 2.1 add style to builder
.setStyle(bigPicStyle)
.setLargeIcon(eggImage)
- Chạy ứng dụng và đặt một đồng hồ hẹn giờ. Khi thông báo xuất hiện lần đầu, thông báo sẽ ở trạng thái thu gọn trong ngăn thông báo. Nếu bạn mở rộng thông báo, một hình ảnh lớn sẽ xuất hiện trong vùng thông báo mở rộng.
Bước 2: Các hành động trên thông báo
Thao tác trên thông báo là một điểm tuỳ chỉnh khác mà bạn có thể thêm vào thông báo. Hiện tại, thông báo của bạn sẽ chuyển hướng đến ứng dụng khi người dùng nhấp vào thông báo. Ngoài hành động mặc định này trong thông báo, bạn có thể thêm các nút hành động trong thông báo để hoàn tất một nhiệm vụ liên quan đến ứng dụng.
Thông báo có thể cung cấp tối đa 3 nút thao tác để người dùng phản hồi nhanh, chẳng hạn như tạm ẩn lời nhắc hoặc trả lời tin nhắn văn bản. Các nút thao tác này không được trùng lặp với thao tác được thực hiện khi người dùng nhấn vào thông báo.
Để thêm một nút hành động, hãy truyền một PendingIntent
đến hàm addAction()
trên trình tạo. Thao tác này tương tự như việc thiết lập hành động nhấn mặc định của thông báo bằng cách gọi setContentIntent()
, ngoại trừ việc thay vì chạy một hoạt động, bạn có thể làm nhiều việc khác, chẳng hạn như bắt đầu một BroadcastReceiver
thực hiện một công việc ở chế độ nền để hành động này không làm gián đoạn ứng dụng đang mở.
Trong lớp học lập trình này, bạn đã được cung cấp một BoadcastReceiver
có tên là SnoozeReceiver
. Bạn sẽ dùng SnoozeReceiver
để nhận lượt nhấp của người dùng vào thao tác Thông báo. Trong các bước sau, bạn sẽ thêm mã để tạm ngưng thông báo của đồng hồ hẹn giờ trong 60 giây khi người dùng nhấp vào nút hành động tạm ngưng. Khi người dùng nhấp vào thao tác tạm ngưng, SnoozeReceiver
sẽ nhận được một ý định và tạo một chuông báo mới để gửi thông báo mới sau 60 giây.
- Mở
SnoozeReceiver.kt
. Lớp này tương tự nhưAlarmReceiver
mà bạn đã sử dụng trước đó. Trong các bước sau, bạn sẽ thêm mã để kích hoạt hàmonReceive()
củaSnoozeReceiver
. Nói tóm lại, mã trongSnoozeReceiver
sẽ tạo một chuông báo mới để gửi thông báo mới sau một phút. Di chuyển xuống cuối hàm onReceive, lấy một phiên bản notificationManager từ hệ thống và gọi cancelAll.
// SnoozeReceiver.kt
val notificationManager = ContextCompat.getSystemService(
context,
NotificationManager::class.java
) as NotificationManager
notificationManager.cancelAll()
- Để sử dụng
SnoozeReceiver
, hãy mởNotificationUtils.kt
. - Tạo một
Intent
snoozeIntent
mới choSnoozeReceiver
ngay sau kiểu trong hàmsendNotification()
. - Tạo một ý định đang chờ xử lý bằng cách gọi phương thức
getBroadcast()
trênPendingIntent
. Phương thức này yêu cầu các tham số trong các bước sau. Hệ thống sẽ dùngPendingIntent
này để thiết lập một chuông báo mới nhằm đăng thông báo mới sau 60 giây khi người dùng nhấn vào nút báo lại. - Tham số đầu tiên là bối cảnh ứng dụng mà
PendingIntent
này sẽ bắt đầu hoạt động. - Tham số thứ hai là mã yêu cầu, tức là mã yêu cầu cho ý định đang chờ xử lý này. Nếu cần cập nhật hoặc huỷ ý định đang chờ xử lý này, bạn cần sử dụng mã này để truy cập vào ý định đang chờ xử lý.
- Tiếp theo, hãy thêm đối tượng
snoozeIntent
, đây là ý định của hoạt động sẽ được khởi chạy. - Cuối cùng, hãy thêm giá trị cờ
#FLAG_ONE_SHOT
vì ý định sẽ chỉ được dùng một lần. Thao tác nhanh và thông báo sẽ biến mất sau lần nhấn đầu tiên. Đó là lý do khiến ý định chỉ có thể được dùng một lần.
// NotificationUtils.kt
// TODO: Step 2.2 add snooze action
val snoozeIntent = Intent(applicationContext, SnoozeReceiver::class.java)
val snoozePendingIntent: PendingIntent = PendingIntent.getBroadcast(
applicationContext,
REQUEST_CODE,
snoozeIntent,
FLAGS
)
- Tiếp theo, hãy gọi hàm
addAction()
trênnotificationBuilder
. Hàm này yêu cầu một biểu tượng và văn bản để mô tả hành động của bạn cho người dùng. Bạn cũng cần thêmsnoozeIntent
. Ý định này sẽ được dùng để kích hoạtboadcastReceiver
phù hợp khi người dùng nhấp vào thao tác của bạn.
// NotificationUtils.kt
// TODO: Step 2.3 add snooze action
.addAction(
R.drawable.egg_icon,
applicationContext.getString(R.string.snooze),
snoozePendingIntent
)
- Chạy ứng dụng hẹn giờ để kiểm thử thao tác báo lại.
- Chạy bộ hẹn giờ và đưa ứng dụng vào chế độ nền. Sau khi hết thời gian, hãy mở rộng thông báo và bạn sẽ thấy thông báo hiện có nút hành động báo lại để báo lại đồng hồ đếm ngược thêm một phút.
Bước 3: Mức độ quan trọng của thông báo
Mức độ quan trọng xác định mức độ thông báo nên làm gián đoạn người dùng bằng hình ảnh và âm thanh. Thông báo có mức độ quan trọng cao hơn sẽ gây gián đoạn nhiều hơn cho người dùng.
Bạn phải chỉ định cấp độ quan trọng trong hàm khởi tạo NotificationChannel
. Ban đầu, bạn đặt mức độ quan trọng thấp cho ứng dụng hẹn giờ. Bạn có thể sử dụng một trong năm mức độ quan trọng, từ IMPORTANCE_NONE(0)
đến IMPORTANCE_HIGH(4)
. Mức độ quan trọng mà bạn chỉ định cho một kênh sẽ áp dụng cho tất cả thông báo mà bạn đăng lên kênh đó.
Các mức độ quan trọng của kênh
Mức độ quan trọng mà người dùng nhìn thấy | Mức độ quan trọng (Android 8.0 trở lên) | Mức độ ưu tiên (Android 7.1 trở xuống) |
Phát ra âm thanh và xuất hiện dưới dạng thông báo quan trọng (hiển thị ở đầu màn hình) | ||
Phát ra âm thanh | ||
Không có âm thanh | ||
Không có âm thanh và không xuất hiện trong thanh trạng thái |
Để biết thông tin về cách chọn mức độ ưu tiên phù hợp, hãy xem phần "Mức độ ưu tiên" trong Hướng dẫn thiết kế thông báo. Bạn nên cẩn thận khi chọn mức độ quan trọng cho các thông báo trong ứng dụng. Bạn nên chọn mức độ quan trọng của kênh sao cho phù hợp với thời gian và sự chú ý của người dùng. Khi một thông báo không quan trọng được ngụy trang thành thông báo khẩn cấp, thông báo đó có thể gây ra cảnh báo không cần thiết và gây sao lãng. Người dùng có toàn quyền kiểm soát mức độ quan trọng của thông báo. Vì vậy, nếu bạn tạo một thông báo gây phiền toái, họ có thể tắt hoàn toàn kênh thông báo của bạn.
Khi bạn tạo thông báo lần đầu tiên ở Bước 1.6, bộ hẹn giờ đã được đặt để gửi thông báo có mức độ ưu tiên thấp vì được thiết kế để không làm phiền người dùng bằng thông báo. Tuy nhiên, bạn nên thu hút sự chú ý của người dùng trước khi trứng chín quá. Để thay đổi mức độ quan trọng của thông báo, hãy bắt đầu bằng chế độ cài đặt kênh. Mức độ quan trọng của kênh ảnh hưởng đến mức độ gián đoạn của tất cả thông báo được đăng trong kênh và phải được chỉ định trong hàm khởi tạo NotificationChannel
.
- Để thay đổi mức độ quan trọng của kênh thông báo của ứng dụng, hãy mở
EggTimerFragment.kt
rồi chuyển đếncreateChannel()
. Thay đổi mức độ quan trọng từIMPORTANCE_LOW
thànhIMPORTANCE_HIGH
.
// EggTimerFragment.kt
val notificationChannel = NotificationChannel(
channelId,
channelName,
// TODO: Step 2.4 change importance
NotificationManager.IMPORTANCE_HIGH
)
Để hỗ trợ các thiết bị chạy Android 7.1 (API cấp 25) trở xuống, bạn cũng phải gọi setPriority()
cho từng thông báo, bằng cách sử dụng hằng số ưu tiên từ lớp NotificationCompat
.
- Mở
NotificationUtils.kt
rồi thêm nội dung sau vào đối tượng trình tạo thông báo.
// NotificationUtils.kt
.addAction(
R.drawable.common_google_signin_btn_icon_dark,
applicationContext.getString(R.string.snooze),
snoozePendingIntent
)
// TODO: Step 2.5 set priority
.setPriority(NotificationCompat.PRIORITY_HIGH)
- Trước khi chạy ứng dụng, hãy nhấp và giữ biểu tượng ứng dụng trên thiết bị hoặc trình mô phỏng rồi chọn gỡ cài đặt để xoá các chế độ cài đặt kênh trước đó. Nếu bạn không gỡ cài đặt ứng dụng, chế độ cài đặt mức độ ưu tiên của kênh sẽ không thay đổi và điều này sẽ dẫn đến việc không có thay đổi về hành vi khi thông báo được đăng.
- Bây giờ, hãy chạy lại ứng dụng và bắt đầu hẹn giờ. Lần này, khi thông báo được gửi, bạn sẽ thấy một cửa sổ bật lên xuất hiện ở đầu màn hình, bất kể ứng dụng của bạn đang chạy ở nền trước hay nền sau.
Bước 4: Huy hiệu thông báo
Huy hiệu thông báo là những dấu chấm nhỏ xuất hiện trên biểu tượng trình chạy của ứng dụng liên kết khi ứng dụng có một thông báo đang hoạt động. Người dùng có thể nhấn và giữ biểu tượng ứng dụng để xem các thông báo.
Theo mặc định, các dấu chấm này (gọi là huy hiệu) sẽ xuất hiện và ứng dụng của bạn không cần làm gì cả. Tuy nhiên, có thể có những trường hợp huy hiệu không phù hợp với thông báo của bạn, vì vậy, bạn có thể tắt huy hiệu theo từng kênh bằng cách gọi setShowBadge(false)
trên đối tượng NotificationChannel
. Vì đồng hồ hẹn giờ chỉ có một thông báo đang hoạt động tại một thời điểm nhất định, nên huy hiệu trên biểu tượng ứng dụng của bạn không mang lại nhiều lợi ích cho người dùng. Trong các bước sau, bạn sẽ tắt huy hiệu và chỉ hiện thông báo cho đồng hồ hẹn giờ.
- Thêm
setShowBadge(false)
vào mã tạo kênh cho đồng hồ hẹn giờ để tắt huy hiệu.
// EggTimerFragment.kt
).apply {
// TODO: Step 2.6 disable badges for this channel
setShowBadge(false)
}
- Chạy lại ứng dụng, bắt đầu hẹn giờ và quan sát biểu tượng ứng dụng. Bạn sẽ không thấy huy hiệu nào trên biểu tượng ứng dụng.
Đoạn mã giải pháp nằm trong nhánh chính của mã đã tải xuống.
- Sử dụng lớp NotificationManager để tạo, gửi, cập nhật và huỷ thông báo.
- Sử dụng đối tượng NotificationChannel với phương thức createNotificationChannel để đặt một kênh cho thông báo.
- Sử dụng addAction() để thêm các thao tác nhanh vào thông báo.
- Sử dụng setShowBadge() để bật hoặc tắt huy hiệu.
- Tạo kiểu cho thông báo bằng cách sử dụng các kiểu mở rộng từ Notification.Style
- Đặt mức độ quan trọng bằng NotificationChannel.setImportance()
Khoá học của Udacity:
Tài liệu dành cho nhà phát triển Android:
Để biết đường liên kết đến các lớp học lập trình khác trong khoá học này, hãy xem trang đích của các lớp học lập trình trong khoá học Kiến thức nâng cao về cách tạo ứng dụng Android bằng Kotlin.