Tạo một thông báo

Thông báo cung cấp thông tin ngắn gọn và kịp thời về các sự kiện trong ứng dụng khi không được sử dụng. Tài liệu này hướng dẫn bạn cách tạo một thông báo có nhiều tính năng. Để tìm hiểu cách thông báo xuất hiện trên Android, hãy xem bài viết Tổng quan về thông báo. Để biết mã mẫu sử dụng thông báo, hãy xem Mẫu mọi người trên GitHub.

Mã trong trang này sử dụng các API NotificationCompat trong Thư viện AndroidX. Các API này cho phép bạn thêm các tính năng chỉ có trên các phiên bản Android mới hơn trong khi vẫn cung cấp khả năng tương thích với Android 9 (API cấp 28). Tuy nhiên, một số tính năng, chẳng hạn như thao tác trả lời cùng dòng, khiến các phiên bản trước đó không hoạt động.

Thêm Thư viện cốt lõi AndroidX

Mặc dù hầu hết dự án được tạo bằng Android Studio đều có các phần phụ thuộc cần thiết để sử dụng NotificationCompat, nhưng hãy xác minh rằng tệp build.gradle cấp mô-đun của bạn có phần phụ thuộc sau:

Groovy

dependencies {
    implementation "androidx.core:core:2.2.0"
}

Kotlin

dependencies {
    implementation("androidx.core:core-ktx:2.2.0")
}

Tạo thông báo cơ bản

Thông báo ở dạng cơ bản và thu gọn nhất (còn gọi là biểu mẫu thu gọn) sẽ hiển thị một biểu tượng, tiêu đề và một lượng nhỏ nội dung văn bản. Phần này cho biết cách tạo thông báo mà người dùng có thể nhấn để khởi chạy một hoạt động trong ứng dụng của bạn.

Hình 1. Một thông báo có biểu tượng, tiêu đề và văn bản.

Để biết thêm thông tin chi tiết về từng phần của thông báo, hãy đọc phần phân tích thông báo.

Khai báo quyền khi bắt đầu chạy

Android 13 (API cấp 33) trở lên hỗ trợ quyền khi bắt đầu chạy để đăng các thông báo không được miễn trừ (bao gồm cả Dịch vụ trên nền trước (FGS)) qua một ứng dụng.

Quyền mà bạn cần khai báo trong tệp kê khai của ứng dụng sẽ xuất hiện trong đoạn mã sau:

<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>

Để biết thêm thông tin chi tiết về các quyền khi bắt đầu chạy, hãy xem bài viết Quyền khi bắt đầu chạy thông báo.

Thiết lập nội dung thông báo

Để bắt đầu, hãy thiết lập nội dung và kênh của thông báo bằng cách sử dụng đối tượng NotificationCompat.Builder. Ví dụ sau đây cho biết cách tạo một thông báo bằng những nội dung sau:

  • Một biểu tượng nhỏ, do setSmallIcon() đặt. Đây là nội dung duy nhất mà người dùng cần nhìn thấy.

  • Một tiêu đề, do setContentTitle() đặt.

  • Văn bản nội dung do setContentText() đặt.

  • Mức độ ưu tiên của thông báo, do setPriority() đặt. Mức độ ưu tiên xác định mức độ xâm nhập của thông báo trên Android 7.1 trở xuống. Đối với Android 8.0 trở lên, hãy đặt tầm quan trọng của kênh như minh hoạ trong phần tiếp theo.

Kotlin

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle(textTitle)
        .setContentText(textContent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)

Java

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle(textTitle)
        .setContentText(textContent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

Hàm khởi tạo NotificationCompat.Builder yêu cầu bạn cung cấp mã nhận dạng kênh. Đây là yêu cầu bắt buộc để tương thích với Android 8.0 (API cấp 26) trở lên, nhưng các phiên bản cũ sẽ bỏ qua.

Theo mặc định, nội dung văn bản của thông báo sẽ được cắt bớt cho vừa với một dòng. Bạn có thể hiển thị thêm thông tin bằng cách tạo một thông báo có thể mở rộng.

Hình 2. Thông báo có thể mở rộng ở dạng thu gọn và mở rộng.

Nếu muốn thời lượng thông báo dài hơn, bạn có thể bật thông báo có thể mở rộng bằng cách thêm mẫu kiểu với setStyle(). Ví dụ: mã sau đây sẽ tạo ra một vùng văn bản lớn hơn:

Kotlin

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Much longer text that cannot fit one line...")
        .setStyle(NotificationCompat.BigTextStyle()
                .bigText("Much longer text that cannot fit one line..."))
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)

Java

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Much longer text that cannot fit one line...")
        .setStyle(new NotificationCompat.BigTextStyle()
                .bigText("Much longer text that cannot fit one line..."))
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

Để biết thêm thông tin về các kiểu thông báo lớn khác, bao gồm cả cách thêm hình ảnh và bộ điều khiển chế độ phát nội dung nghe nhìn, hãy xem phần Tạo thông báo có thể mở rộng.

Tạo kênh và thiết lập tầm quan trọng

Trước khi có thể phân phối thông báo trên Android 8.0 trở lên, hãy đăng ký kênh thông báo của ứng dụng với hệ thống bằng cách truyền một thực thể của NotificationChannel tới createNotificationChannel(). Mã sau đây bị chặn bởi một điều kiện trên phiên bản SDK_INT:

Kotlin

private fun createNotificationChannel() {
    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is not in the Support Library.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val name = getString(R.string.channel_name)
        val descriptionText = getString(R.string.channel_description)
        val importance = NotificationManager.IMPORTANCE_DEFAULT
        val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
            description = descriptionText
        }
        // Register the channel with the system.
        val notificationManager: NotificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }
}

Java

private void createNotificationChannel() {
    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is not in the Support Library.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        CharSequence name = getString(R.string.channel_name);
        String description = getString(R.string.channel_description);
        int importance = NotificationManager.IMPORTANCE_DEFAULT;
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
        channel.setDescription(description);
        // Register the channel with the system; you can't change the importance
        // or other notification behaviors after this.
        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        notificationManager.createNotificationChannel(channel);
    }
}

Vì bạn phải tạo kênh thông báo trước khi đăng bất kỳ thông báo nào trên Android 8.0 trở lên, hãy thực thi mã này ngay khi ứng dụng khởi động. Bạn có thể an toàn gọi lệnh này nhiều lần vì việc tạo một kênh thông báo hiện có sẽ không thực hiện thao tác nào.

Hàm khởi tạo NotificationChannel yêu cầu importance, sử dụng một trong các hằng số của lớp NotificationManager. Tham số này xác định cách làm gián đoạn người dùng đối với mọi thông báo thuộc kênh này. Đặt mức độ ưu tiên bằng setPriority() để hỗ trợ Android 7.1 trở xuống, như trong ví dụ trước.

Mặc dù bạn phải đặt mức độ quan trọng hoặc mức độ ưu tiên của thông báo như trong ví dụ sau, nhưng hệ thống không đảm bảo hành vi cảnh báo mà bạn nhận được. Trong một số trường hợp, hệ thống có thể thay đổi mức độ quan trọng dựa trên các yếu tố khác và người dùng luôn có thể xác định lại mức độ quan trọng cho một kênh nhất định.

Để biết thêm thông tin về ý nghĩa của các cấp độ, hãy đọc bài viết về các mức độ quan trọng của thông báo.

Đặt thao tác nhấn của thông báo

Mọi thông báo phải phản hồi một lượt nhấn, thường là để mở một hoạt động trong ứng dụng tương ứng với thông báo đó. Để làm vậy, hãy chỉ định ý định nội dung được xác định bằng đối tượng PendingIntent rồi truyền đối tượng đó đến setContentIntent().

Đoạn mã sau đây cho biết cách tạo ý định cơ bản để mở một hoạt động khi người dùng nhấn vào thông báo:

Kotlin

// Create an explicit intent for an Activity in your app.
val intent = Intent(this, AlertDetails::class.java).apply {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)

val builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        // Set the intent that fires when the user taps the notification.
        .setContentIntent(pendingIntent)
        .setAutoCancel(true)

Java

// Create an explicit intent for an Activity in your app.
Intent intent = new Intent(this, AlertDetails.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        // Set the intent that fires when the user taps the notification.
        .setContentIntent(pendingIntent)
        .setAutoCancel(true);

Đoạn mã này gọi setAutoCancel(). Mã này sẽ tự động xoá thông báo khi người dùng nhấn vào thông báo đó.

Phương thức setFlags() hiển thị trong ví dụ trước duy trì trải nghiệm điều hướng dự kiến của người dùng sau khi họ mở ứng dụng bằng thông báo. Bạn nên sử dụng đối tượng này tuỳ thuộc vào loại hoạt động bạn đang bắt đầu, có thể là một trong các loại hoạt động sau:

  • Một hoạt động chỉ dành cho các phản hồi thông báo. Không có lý do nào khiến người dùng chuyển đến hoạt động này trong quá trình sử dụng ứng dụng bình thường. Vì vậy, hoạt động này sẽ bắt đầu một tác vụ mới thay vì được thêm vào tác vụ và ngăn xếp lui hiện có của ứng dụng. Đây là loại ý định được tạo trong mẫu trước đó.

  • Một hoạt động tồn tại trong luồng ứng dụng thông thường của ứng dụng. Trong trường hợp này, việc khởi động hoạt động sẽ tạo ra một ngăn xếp lui để giữ nguyên kỳ vọng của người dùng đối với các nút Quay lại và Mũi tên lên.

Để biết thêm về các cách định cấu hình ý định của thông báo, hãy xem phần Bắt đầu hoạt động từ thông báo.

Hiện thông báo

Để thông báo xuất hiện, hãy gọi NotificationManagerCompat.notify(), truyền vào đó một mã nhận dạng duy nhất cho thông báo và kết quả của NotificationCompat.Builder.build(). Lệnh này được minh hoạ trong ví dụ sau:

Kotlin

with(NotificationManagerCompat.from(this)) {
    if (ActivityCompat.checkSelfPermission(
            this@MainActivity,
            Manifest.permission.POST_NOTIFICATIONS
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        // TODO: Consider calling
        // ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        // public fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,
        //                                        grantResults: IntArray)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.

        return@with
    }
    // notificationId is a unique int for each notification that you must define.
    notify(NOTIFICATION_ID, builder.build())
}

Java

with(NotificationManagerCompat.from(this)) {
   if (ActivityCompat.checkSelfPermission(
           this@MainActivity,
           Manifest.permission.POST_NOTIFICATIONS
       ) != PackageManager.PERMISSION_GRANTED
   ) {
       // TODO: Consider calling
       // ActivityCompat#requestPermissions
       // here to request the missing permissions, and then overriding
       // public void onRequestPermissionsResult(int requestCode, String[] permissions,
       //                                        int[] grantResults)
       // to handle the case where the user grants the permission. See the documentation
       // for ActivityCompat#requestPermissions for more details.

       return
   }
   // notificationId is a unique int for each notification that you must define.
   notify(NOTIFICATION_ID, builder.build())
}

Lưu mã thông báo mà bạn truyền vào NotificationManagerCompat.notify(), vì bạn sẽ cần mã này khi muốn cập nhật hoặc xoá thông báo.

Ngoài ra, để kiểm thử các thông báo cơ bản trên thiết bị chạy Android 13 trở lên, hãy bật thông báo theo cách thủ công hoặc tạo một hộp thoại để yêu cầu gửi thông báo.

Thêm nút hành động

Một thông báo có thể cung cấp tối đa 3 nút hành động cho phép người dùng phản hồi nhanh chóng, chẳng hạn như tạm hoãn lời nhắc hoặc trả lời một tin nhắn văn bản. Tuy nhiên, các nút hành động này không được trùng lặp với hành động được thực hiện khi người dùng nhấn vào thông báo.

Hình 3. Thông báo kèm một nút hành động.

Để thêm một nút hành động, hãy chuyển PendingIntent vào phương thức addAction(). Điều này giống như thiết lập thao tác nhấn mặc định của thông báo, ngoại trừ thay vì khởi chạy một hoạt động, bạn có thể làm những việc khác như bắt đầu BroadcastReceiver thực hiện công việc trong nền để thao tác này không làm gián đoạn ứng dụng đã mở.

Ví dụ: Mã sau đây cho biết cách gửi thông báo đến một trình thu nhận cụ thể:

Kotlin


val ACTION_SNOOZE = "snooze"

val snoozeIntent = Intent(this, MyBroadcastReceiver::class.java).apply {
    action = ACTION_SNOOZE
    putExtra(EXTRA_NOTIFICATION_ID, 0)
}
val snoozePendingIntent: PendingIntent =
    PendingIntent.getBroadcast(this, 0, snoozeIntent, 0)
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        .addAction(R.drawable.ic_snooze, getString(R.string.snooze),
                snoozePendingIntent)

Java


String ACTION_SNOOZE = "snooze"

Intent snoozeIntent = new Intent(this, MyBroadcastReceiver.class);
snoozeIntent.setAction(ACTION_SNOOZE);
snoozeIntent.putExtra(EXTRA_NOTIFICATION_ID, 0);
PendingIntent snoozePendingIntent =
        PendingIntent.getBroadcast(this, 0, snoozeIntent, 0);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        .addAction(R.drawable.ic_snooze, getString(R.string.snooze),
                snoozePendingIntent);

Để biết thêm thông tin về cách xây dựng BroadcastReceiver nhằm chạy công việc ở chế độ nền, hãy xem bài viết Tổng quan về thông báo truyền tin.

Thay vào đó, nếu bạn đang cố gắng tạo thông báo bằng các nút phát nội dung đa phương tiện, chẳng hạn như tạm dừng và bỏ qua bản nhạc, hãy xem cách tạo thông báo bằng các nút điều khiển nội dung nghe nhìn.

Thêm thao tác trả lời trực tiếp

Thao tác trả lời trực tiếp (có trong Android 7.0 (API cấp 24)) cho phép người dùng nhập văn bản trực tiếp vào thông báo. Sau đó, văn bản này sẽ được gửi đến ứng dụng của bạn mà không cần mở hoạt động. Ví dụ: bạn có thể sử dụng thao tác trả lời trực tiếp để cho phép người dùng trả lời tin nhắn văn bản hoặc cập nhật danh sách việc cần làm ngay trong thông báo.

Hình 4. Thao tác nhấn vào nút "Trả lời" sẽ mở phương thức nhập văn bản.

Thao tác trả lời trực tiếp sẽ xuất hiện dưới dạng một nút bổ sung trong thông báo mở ra văn bản nhập. Khi người dùng nhập xong, hệ thống sẽ đính kèm phản hồi bằng văn bản vào ý định mà bạn chỉ định cho thao tác thông báo và gửi ý định đó đến ứng dụng của bạn.

Thêm nút trả lời

Để tạo một thao tác thông báo hỗ trợ tính năng trả lời trực tiếp, hãy làm theo các bước sau:

  1. Tạo một thực thể của RemoteInput.Builder mà bạn có thể thêm vào thao tác thông báo. Hàm khởi tạo của lớp này chấp nhận một chuỗi mà hệ thống dùng làm khoá cho việc nhập văn bản. Sau đó, ứng dụng của bạn sẽ sử dụng khoá đó để truy xuất văn bản của dữ liệu đầu vào.

    Kotlin

      // Key for the string that's delivered in the action's intent.
      private val KEY_TEXT_REPLY = "key_text_reply"
      var replyLabel: String = resources.getString(R.string.reply_label)
      var remoteInput: RemoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).run {
          setLabel(replyLabel)
          build()
      }
      

    Java

      // Key for the string that's delivered in the action's intent.
      private static final String KEY_TEXT_REPLY = "key_text_reply";
    
      String replyLabel = getResources().getString(R.string.reply_label);
      RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
              .setLabel(replyLabel)
              .build();
      
  2. Tạo một PendingIntent cho thao tác trả lời.

    Kotlin

      // Build a PendingIntent for the reply action to trigger.
      var replyPendingIntent: PendingIntent =
          PendingIntent.getBroadcast(applicationContext,
              conversation.getConversationId(),
              getMessageReplyIntent(conversation.getConversationId()),
              PendingIntent.FLAG_UPDATE_CURRENT)
      

    Java

      // Build a PendingIntent for the reply action to trigger.
      PendingIntent replyPendingIntent =
              PendingIntent.getBroadcast(getApplicationContext(),
                      conversation.getConversationId(),
                      getMessageReplyIntent(conversation.getConversationId()),
                      PendingIntent.FLAG_UPDATE_CURRENT);
      
  3. Đính kèm đối tượng RemoteInput vào một thao tác bằng addRemoteInput().

    Kotlin

      // Create the reply action and add the remote input.
      var action: NotificationCompat.Action =
          NotificationCompat.Action.Builder(R.drawable.ic_reply_icon,
              getString(R.string.label), replyPendingIntent)
              .addRemoteInput(remoteInput)
              .build()
      

    Java

      // Create the reply action and add the remote input.
      NotificationCompat.Action action =
              new NotificationCompat.Action.Builder(R.drawable.ic_reply_icon,
                      getString(R.string.label), replyPendingIntent)
                      .addRemoteInput(remoteInput)
                      .build();
      
  4. Áp dụng thao tác cho một thông báo và đưa ra thông báo.

    Kotlin

      // Build the notification and add the action.
      val newMessageNotification = Notification.Builder(context, CHANNEL_ID)
              .setSmallIcon(R.drawable.ic_message)
              .setContentTitle(getString(R.string.title))
              .setContentText(getString(R.string.content))
              .addAction(action)
              .build()
    
      // Issue the notification.
      with(NotificationManagerCompat.from(this)) {
          notificationManager.notify(notificationId, newMessageNotification)
      }
      

    Java

      // Build the notification and add the action.
      Notification newMessageNotification = new Notification.Builder(context, CHANNEL_ID)
              .setSmallIcon(R.drawable.ic_message)
              .setContentTitle(getString(R.string.title))
              .setContentText(getString(R.string.content))
              .addAction(action)
              .build();
    
      // Issue the notification.
      NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
      notificationManager.notify(notificationId, newMessageNotification);
      

Hệ thống nhắc người dùng nhập một phản hồi khi họ kích hoạt thao tác thông báo, như minh hoạ trong hình 4.

Truy xuất hoạt động đầu vào của người dùng qua câu trả lời

Để nhận hoạt động đầu vào của người dùng từ giao diện người dùng trả lời của thông báo, hãy gọi hàm RemoteInput.getResultsFromIntent(), truyền vào đó IntentBroadcastReceiver nhận được:

Kotlin

private fun getMessageText(intent: Intent): CharSequence? {
    return RemoteInput.getResultsFromIntent(intent)?.getCharSequence(KEY_TEXT_REPLY)
}

Java

private CharSequence getMessageText(Intent intent) {
    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
    if (remoteInput != null) {
        return remoteInput.getCharSequence(KEY_TEXT_REPLY);
    }
    return null;
 }

Sau khi xử lý văn bản, hãy cập nhật thông báo bằng cách gọi NotificationManagerCompat.notify() với cùng một mã nhận dạng và thẻ (nếu được sử dụng). Điều này là cần thiết để ẩn giao diện người dùng trả lời trực tiếp và xác nhận với người dùng rằng câu trả lời của họ đã được nhận và xử lý đúng cách.

Kotlin

// Build a new notification, which informs the user that the system
// handled their interaction with the previous notification.
val repliedNotification = Notification.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_message)
        .setContentText(getString(R.string.replied))
        .build()

// Issue the new notification.
NotificationManagerCompat.from(this).apply {
    notificationManager.notify(notificationId, repliedNotification)
}

Java

// Build a new notification, which informs the user that the system
// handled their interaction with the previous notification.
Notification repliedNotification = new Notification.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_message)
        .setContentText(getString(R.string.replied))
        .build();

// Issue the new notification.
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(notificationId, repliedNotification);

Khi làm việc với thông báo mới này, hãy sử dụng ngữ cảnh được chuyển đến phương thức onReceive() của trình thu.

Thêm câu trả lời vào cuối thông báo bằng cách gọi setRemoteInputHistory(). Tuy nhiên, nếu bạn đang xây dựng một ứng dụng nhắn tin, hãy tạo một thông báo kiểu nhắn tin và thêm tin nhắn mới vào cuộc trò chuyện.

Để biết thêm lời khuyên về thông báo của ứng dụng nhắn tin, hãy xem phần các phương pháp hay nhất dành cho ứng dụng nhắn tin.

Thêm thanh tiến trình

Thông báo có thể bao gồm chỉ báo tiến trình dạng ảnh động cho người dùng biết trạng thái của một hoạt động đang diễn ra.

Hình 5. Thanh tiến trình trong một thao tác.

Nếu bạn có thể ước tính mức độ hoàn thành thao tác bất cứ lúc nào, hãy sử dụng dạng "xác định" của chỉ báo (như trong hình 5) bằng cách gọi setProgress(max, progress, false). Thông số đầu tiên là giá trị "complete", chẳng hạn như 100. Thứ hai là lượng nội dung cần hoàn thành. Giá trị cuối cùng cho biết đây là thanh tiến trình xác định.

Khi thao tác của bạn tiếp tục, hãy liên tục gọi setProgress(max, progress, false) với một giá trị đã cập nhật cho progress và phát hành lại thông báo, như minh hoạ trong ví dụ sau.

Kotlin

val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
    setContentTitle("Picture Download")
    setContentText("Download in progress")
    setSmallIcon(R.drawable.ic_notification)
    setPriority(NotificationCompat.PRIORITY_LOW)
}
val PROGRESS_MAX = 100
val PROGRESS_CURRENT = 0
NotificationManagerCompat.from(this).apply {
    // Issue the initial notification with zero progress.
    builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false)
    notify(notificationId, builder.build())

    // Do the job that tracks the progress here.
    // Usually, this is in a worker thread.
    // To show progress, update PROGRESS_CURRENT and update the notification with:
    // builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
    // notificationManager.notify(notificationId, builder.build());

    // When done, update the notification once more to remove the progress bar.
    builder.setContentText("Download complete")
            .setProgress(0, 0, false)
    notify(notificationId, builder.build())
}

Java

...
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
builder.setContentTitle("Picture Download")
        .setContentText("Download in progress")
        .setSmallIcon(R.drawable.ic_notification)
        .setPriority(NotificationCompat.PRIORITY_LOW);

// Issue the initial notification with zero progress.
int PROGRESS_MAX = 100;
int PROGRESS_CURRENT = 0;
builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
notificationManager.notify(notificationId, builder.build());

// Do the job that tracks the progress here.
// Usually, this is in a worker thread.
// To show progress, update PROGRESS_CURRENT and update the notification with:
// builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
// notificationManager.notify(notificationId, builder.build());

// When done, update the notification once more to remove the progress bar.
builder.setContentText("Download complete")
        .setProgress(0,0,false);
notificationManager.notify(notificationId, builder.build());

Khi kết thúc toán tử, progress phải bằng max. Bạn có thể rời khỏi thanh tiến trình để cho biết thao tác đã hoàn tất hoặc xoá thao tác đó. Trong cả hai trường hợp, hãy cập nhật văn bản thông báo để cho biết thao tác đã hoàn tất. Để xoá thanh tiến trình, hãy gọi setProgress(0, 0, false).

Để hiển thị thanh tiến trình không xác định (thanh không cho biết tỷ lệ phần trăm hoàn thành), hãy gọi setProgress(0, 0, true). Kết quả là một chỉ báo có cùng kiểu với thanh tiến trình trước đó, ngoại trừ việc đó là một ảnh động liên tục không cho biết là đã hoàn thành. Ảnh động tiến trình sẽ chạy cho đến khi bạn gọi setProgress(0, 0, false), sau đó cập nhật thông báo để xoá chỉ báo hoạt động.

Hãy nhớ thay đổi văn bản thông báo để cho biết thao tác đã hoàn tất.

Đặt danh mục trên toàn hệ thống

Android sử dụng các danh mục được xác định trước trên toàn hệ thống để xác định xem có nên làm phiền người dùng bằng một thông báo nhất định hay không khi người dùng bật chế độ Không làm phiền.

Nếu thông báo của bạn thuộc một trong các danh mục thông báo đã xác định trong NotificationCompat – chẳng hạn như CATEGORY_ALARM, CATEGORY_REMINDER, CATEGORY_EVENT hoặc CATEGORY_CALL – hãy khai báo thông báo đó bằng cách chuyển danh mục thích hợp đến setCategory():

Kotlin

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setCategory(NotificationCompat.CATEGORY_MESSAGE)

Java

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setCategory(NotificationCompat.CATEGORY_MESSAGE);

Hệ thống sử dụng thông tin này về danh mục thông báo của bạn để đưa ra quyết định về việc hiển thị thông báo khi thiết bị ở chế độ Không làm phiền. Tuy nhiên, bạn không bắt buộc phải đặt danh mục trên toàn hệ thống. Bạn chỉ nên làm như vậy nếu thông báo của bạn khớp với một trong các danh mục được xác định trong NotificationCompat.

Hiện thông báo khẩn cấp

Ứng dụng của bạn có thể cần hiển thị thông báo khẩn cấp và có giới hạn về thời gian, chẳng hạn như cuộc gọi điện thoại đến hoặc chuông báo đang kêu. Trong những trường hợp này, bạn có thể liên kết ý định truy cập chế độ toàn màn hình với thông báo của mình.

Khi thông báo được gọi, người dùng sẽ thấy một trong các trạng thái sau, tuỳ thuộc vào trạng thái khoá của thiết bị:

  • Nếu thiết bị của người dùng đang khoá, thì một hoạt động toàn màn hình sẽ xuất hiện, che phủ màn hình khoá.
  • Nếu thiết bị của người dùng đã mở khoá, thì thông báo sẽ xuất hiện ở dạng mở rộng bao gồm các tuỳ chọn để xử lý hoặc đóng thông báo.

Đoạn mã sau đây minh hoạ cách liên kết thông báo của bạn với ý định toàn màn hình:

Kotlin

val fullScreenIntent = Intent(this, ImportantActivity::class.java)
val fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
    fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setFullScreenIntent(fullScreenPendingIntent, true)

Java

Intent fullScreenIntent = new Intent(this, ImportantActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
        fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setFullScreenIntent(fullScreenPendingIntent, true);

Đặt chế độ hiển thị màn hình khoá

Để kiểm soát mức độ chi tiết hiển thị trong thông báo từ màn hình khoá, hãy gọi setVisibility() rồi chỉ định một trong các giá trị sau:

  • VISIBILITY_PUBLIC: toàn bộ nội dung của thông báo sẽ xuất hiện trên màn hình khoá.

  • VISIBILITY_SECRET: không có phần nào của thông báo xuất hiện trên màn hình khoá.

  • VISIBILITY_PRIVATE: chỉ thông tin cơ bản, chẳng hạn như biểu tượng của thông báo và tiêu đề nội dung, mới xuất hiện trên màn hình khoá. Toàn bộ nội dung của thông báo không hiển thị.

Khi đặt VISIBILITY_PRIVATE, bạn cũng có thể cung cấp phiên bản thay thế của nội dung thông báo để ẩn một số thông tin chi tiết. Ví dụ: một ứng dụng SMS có thể hiển thị thông báo "Bạn có 3 tin nhắn văn bản mới", nhưng lại ẩn nội dung tin nhắn và người gửi. Để cung cấp thông báo thay thế này, trước tiên, hãy tạo thông báo thay thế bằng NotificationCompat.Builder như bình thường. Sau đó, hãy đính kèm thông báo thay thế vào thông báo thông thường bằng setPublicVersion().

Lưu ý rằng người dùng luôn có quyền kiểm soát tối ưu đối với việc thông báo của họ có hiển thị trên màn hình khoá hay không và có thể kiểm soát thông báo đó dựa trên kênh thông báo của ứng dụng.

Cập nhật thông báo

Để cập nhật một thông báo sau khi phát hành, hãy gọi lại NotificationManagerCompat.notify(), truyền vào thông báo đó cùng mã nhận dạng mà bạn đã sử dụng trước đó. Nếu thông báo trước đó bị đóng, thì một thông báo mới sẽ được tạo.

Bạn có thể tuỳ ý gọi setOnlyAlertOnce() để thông báo làm gián đoạn người dùng (kèm theo âm thanh, chế độ rung hoặc hình ảnh) chỉ vào lần đầu tiên thông báo xuất hiện và không phải trong các bản cập nhật sau này.

Xoá thông báo

Thông báo vẫn hiển thị cho đến khi một trong các điều sau xảy ra:

  • Người dùng đóng thông báo.
  • Người dùng nhấn vào thông báo nếu bạn gọi setAutoCancel() khi tạo thông báo.
  • Bạn gọi cancel() để biết mã thông báo cụ thể. Phương thức này cũng xoá các thông báo hiển thị liên tục.
  • Bạn gọi hàm cancelAll() để xoá tất cả thông báo mà bạn đã gửi trước đó.
  • Thời lượng đã chỉ định sẽ kết thúc, nếu bạn đặt thời gian chờ khi tạo thông báo, bằng cách sử dụng setTimeoutAfter(). Nếu cần, bạn có thể huỷ một thông báo trước khi hết khoảng thời gian chờ đã chỉ định.

Các phương pháp hay nhất dành cho ứng dụng nhắn tin

Hãy cân nhắc các phương pháp hay nhất được nêu ở đây khi tạo thông báo cho ứng dụng nhắn tin và trò chuyện.

Sử dụng MessagingStyle

Kể từ Android 7.0 (API cấp 24), Android sẽ cung cấp một mẫu kiểu thông báo dành riêng cho nội dung nhắn tin. Khi sử dụng lớp NotificationCompat.MessagingStyle, bạn có thể thay đổi một số nhãn hiển thị trên thông báo, bao gồm cả tiêu đề cuộc trò chuyện, các tin nhắn bổ sung và chế độ xem nội dung của thông báo.

Đoạn mã sau đây minh hoạ cách tuỳ chỉnh kiểu của thông báo bằng cách sử dụng lớp MessagingStyle.

Kotlin

val user = Person.Builder()
    .setIcon(userIcon)
    .setName(userName)
    .build()

val notification = NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("2 new messages with $sender")
    .setContentText(subject)
    .setSmallIcon(R.drawable.new_message)
    .setStyle(NotificationCompat.MessagingStyle(user)
        .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getPerson())
        .addMessage(messages[2].getText(), messages[2].getTime(), messages[2].getPerson())
    )
    .build()

Java

Person user = new Person.Builder()
    .setIcon(userIcon)
    .setName(userName)
    .build();

Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("2 new messages with " + sender)
    .setContentText(subject)
    .setSmallIcon(R.drawable.new_message)
    .setStyle(new NotificationCompat.MessagingStyle(user)
        .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getPerson())
        .addMessage(messages[2].getText(), messages[2].getTime(), messages[2].getPerson())
    )
    .build();

Kể từ Android 9.0 (API cấp 28), bạn cũng phải sử dụng lớp Person để kết xuất thông báo và hình đại diện của thông báo một cách tối ưu.

Khi sử dụng NotificationCompat.MessagingStyle, hãy làm như sau:

  • Gọi MessagingStyle.setConversationTitle() để đặt tiêu đề cho các cuộc trò chuyện nhóm có từ 2 người trở lên. Tiêu đề phù hợp có thể là tên của cuộc trò chuyện nhóm hoặc nếu cuộc trò chuyện không có tên, thì danh sách những người tham gia cuộc trò chuyện. Nếu không, thư có thể bị nhầm lẫn là thuộc về cuộc trò chuyện trực tiếp với người gửi tin nhắn gần đây nhất trong cuộc trò chuyện.
  • Sử dụng phương thức MessagingStyle.setData() để đưa các thông điệp nội dung nghe nhìn vào, chẳng hạn như hình ảnh. Hỗ trợ các loại MIME của mẫu image/*.

Sử dụng tính năng Trả lời trực tiếp

Tính năng Trả lời trực tiếp cho phép người dùng trả lời nội tuyến thư.

  • Sau khi người dùng trả lời bằng thao tác trả lời cùng dòng, hãy sử dụng MessagingStyle.addMessage() để cập nhật thông báo MessagingStyle và không rút lại hoặc huỷ thông báo. Việc không huỷ thông báo cho phép người dùng gửi nhiều câu trả lời từ thông báo.
  • Để thao tác trả lời cùng dòng tương thích với Wear OS, hãy gọi Action.WearableExtender.setHintDisplayInlineAction(true).
  • Sử dụng phương thức addHistoricMessage() để cung cấp ngữ cảnh cho một cuộc trò chuyện trả lời trực tiếp bằng cách thêm các tin nhắn trước đây vào thông báo.

Bật tính năng Trả lời thông minh

  • Để bật tính năng Trả lời thông minh, hãy gọi hàm setAllowGeneratedResponses(true) trên thao tác trả lời. Tính năng này giúp người dùng có thể sử dụng phản hồi của tính năng Trả lời thông minh khi thông báo được kết nối với thiết bị Wear OS. Phản hồi của tính năng Trả lời thông minh do một mô hình học máy hoàn toàn trên đồng hồ tạo ra bằng cách sử dụng ngữ cảnh do thông báo NotificationCompat.MessagingStyle cung cấp. Đồng thời, không có dữ liệu nào được tải lên Internet để tạo phản hồi.

Thêm siêu dữ liệu thông báo