Các hoạt động đang diễn ra

Stay organized with collections Save and categorize content based on your preferences.

Trong Wear OS, việc ghép nối một hoạt động đang diễn ra với một thông báo hiển thị liên tục sẽ thêm thông báo đó vào các nền tảng khác trong giao diện người dùng Wear OS. Điều này cho phép người dùng tương tác nhiều hơn với các hoạt động chạy trong thời gian dài.

Thông báo hiển thị liên tục thường được dùng để chỉ báo một thông báo có tác vụ trong nền mà người dùng đang tích cực tương tác, hoặc đang chờ xử lý theo cách nào đó, và do đó sẽ chiếm dụng thiết bị.

Ví dụ: người dùng Wear OS có thể sử dụng một ứng dụng tập thể dục để ghi lại quá trình chạy từ một hoạt động, sau đó rời khỏi ứng dụng đó để bắt đầu một số nhiệm vụ khác. Khi người dùng di chuyển khỏi ứng dụng tập thể dục, ứng dụng thường sẽ chuyển đổi sang một thông báo hiển thị liên tục liên quan đến một số công việc trong nền (ví dụ: các dịch vụ hoặc trình quản lý chuông báo) để người dùng luôn nắm được thông tin về hoạt động của họ khi đang chạy. Thông báo cung cấp cho người dùng thông tin cập nhật và một cách dễ dàng để quay lại ứng dụng.

Tuy nhiên, để xem thông báo này, người dùng phải vuốt vào khay thông báo bên dưới mặt đồng hồ để tìm thông báo phù hợp. Chức năng này không thuận tiện như ở các nền tảng khác.

Nhờ API Ongoing Activity (hoạt động đang diễn ra), thông báo hiển thị liên tục của một ứng dụng có thể đưa thông tin lên nhiều khu vực mới và thuận tiện trên Wear OS nhằm duy trì tương tác với người dùng.

Ví dụ: trong ứng dụng tập thể dục này, thông tin có thể xuất hiện trên mặt đồng hồ của người dùng dưới dạng biểu tượng đang chạy có thể nhấn vào được:

biểu tượng đang chạy

Hình 1. Chỉ báo hoạt động

Phần Recents (Gần đây) của trình chạy ứng dụng chung cũng liệt kê mọi hoạt động đang diễn ra:

trình chạy

Hình 2. Trình chạy chung (Global Launcher)

Sau đây là các tình huống phù hợp để sử dụng một thông báo hiển thị liên tục gắn liền với hoạt động đang diễn ra:

hẹn giờ

Hình 3. Bộ hẹn giờ: Chủ động đếm ngược thời gian và kết thúc khi bộ hẹn giờ tạm dừng/dừng.

bản đồ

Hình 4. Chỉ đường từng chặng Thông báo chỉ đường đến một điểm đến. Kết thúc khi người dùng đến điểm đến hoặc ngừng điều hướng.

âm nhạc

Hình 5. Nội dung nghe nhìn: Phát nhạc trong một phiên. Kết thúc ngay khi người dùng tạm dừng phiên.

Wear tự động tạo các hoạt động đang diễn ra cho Ứng dụng đa phương tiện. Hãy xem lớp học lập trình về Hoạt động đang diễn ra trên GitHub để tìm hiểu ví dụ chuyên sâu về cách tạo hoạt động đang diễn ra cho các loại ứng dụng khác.

Thiết lập

Để bắt đầu sử dụng API Ongoing Activity (hoạt động đang diễn ra) trong ứng dụng, hãy thêm các phần phụ thuộc sau vào tệp build.gradle của ứng dụng:

dependencies {
  implementation "androidx.wear:wear-ongoing:1.0.0"
  // Includes LocusIdCompat and new Notification categories for Ongoing Activity.
  implementation "androidx.core:core:1.6.0"
}

Bắt đầu một hoạt động đang diễn ra

Làm quen với một hoạt động đang diễn ra.

Thông báo hiển thị liên tục

Như đã đề cập ở trên, các hoạt động đang diễn ra liên quan chặt chẽ đến một Thông báo hiển thị liên tục (Ongoing Notification).

Cả hai đều phối hợp hoạt động để thông báo cho người dùng về một nhiệm vụ mà họ đang tích cực thực hiện, hoặc đang chờ xử lý theo cách nào đó, và do đó sẽ chiếm dụng thiết bị.

Bạn phải ghép nối một hoạt động đang diễn ra với một thông báo hiển thị liên tục.

Việc liên kết hoạt động đang diễn ra với một thông báo mang lại nhiều lợi ích như sau:

  • Thông báo là tính năng dự phòng trên các thiết bị không hỗ trợ hoạt động đang diễn ra. Thông báo là nền tảng duy nhất mà ứng dụng của bạn hiển thị khi chạy ở chế độ nền.
  • Trên Android 11 trở lên, Wear OS ẩn thông báo trong khay thông báo khi ứng dụng hiển thị dưới dạng một hoạt động đang diễn ra trên các nền tảng khác.
  • Cách triển khai hiện tại sử dụng chính Notification làm cơ chế giao tiếp.

Các hoạt động đang diễn ra

Bạn chỉ cần bắt đầu một hoạt động đang diễn ra sau khi có thông báo hiển thị liên tục.

Mã mẫu sau đây chứa các ghi chú giúp bạn hiểu ý nghĩa của từng thuộc tính:

Kotlin

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
      …
      .setSmallIcon(..)
      .setOngoing(true)

val ongoingActivityStatus = Status.Builder()
    // Sets the text used across various surfaces.
    .addTemplate(mainText)
    .build()

val ongoingActivity =
    OngoingActivity.Builder(
        applicationContext, NOTIFICATION_ID, notificationBuilder
    )
        // Sets the animated icon that will appear on the watch face in
        // active mode.
        // If it isn't set, the watch face will use the static icon in
        // active mode.
        .setAnimatedIcon(R.drawable.ic_walk)
        // Sets the icon that will appear on the watch face in ambient mode.
        // Falls back to Notification's smallIcon if not set.
        // If neither is set, an Exception is thrown.
        .setStaticIcon(R.drawable.ic_walk)
        // Sets the tap/touch event, so users can re-enter your app from the
        // other surfaces.
        // Falls back to Notification's contentIntent if not set.
        // If neither is set, an Exception is thrown.
        .setTouchIntent(activityPendingIntent)
        // In our case, sets the text used for the Ongoing Activity (more
        // options are available for timers and stopwatches).
        .setStatus(ongoingActivityStatus)
        .build()

ongoingActivity.apply(applicationContext)

notificationManager.notify(NOTIFICATION_ID, builder.build())

Java

NotificationCompat.Builder builder = NotificationCompat.Builder(this, CHANNEL_ID)
      …
      .setSmallIcon(..)
      .setOngoing(true);

OngoingActivityStatus ongoingActivityStatus = OngoingActivityStatus.Builder()
    // Sets the text used across various surfaces.
    .addTemplate(mainText)
    .build();

OngoingActivity ongoingActivity =
    OngoingActivity.Builder(
        applicationContext, NOTIFICATION_ID, notificationBuilder
    )
        // Sets the animated icon that will appear on the watch face in
        // active mode.
        // If it isn't set, the watch face will use the static icon in
        // active mode.
        .setAnimatedIcon(R.drawable.ic_walk)
        // Sets the icon that will appear on the watch face in ambient mode.
        // Falls back to Notification's smallIcon if not set.
        // If neither is set, an Exception is thrown.
        .setStaticIcon(R.drawable.ic_walk)
        // Sets the tap/touch event, so users can re-enter your app from the
        // other surfaces.
        // Falls back to Notification's contentIntent if not set.
        // If neither is set, an Exception is thrown.
        .setTouchIntent(activityPendingIntent)
        // In our case, sets the text used for the Ongoing Activity (more
        // options are available for timers and stopwatches).
        .setStatus(ongoingActivityStatus)
        .build();

ongoingActivity.apply(applicationContext);

notificationManager.notify(NOTIFICATION_ID, builder.build());

Các bước sau đây nêu rõ phần quan trọng nhất trong ví dụ trước:

  1. Gọi .setOngoing(true) trên NotificationCompat.Builder và đặt bất kỳ trường tuỳ chọn nào.

  2. Tạo OngoingActivityStatus để biểu thị văn bản. (Các lựa chọn về trạng thái khác sẽ được đề cập trong phần tiếp theo.)

  3. Tạo OngoingActivity và đặt mã thông báo (bắt buộc).

  4. Gọi apply() trên OngoingActivity theo ngữ cảnh.

  5. Gọi notificationManager.notify() và chuyển vào cùng một mã nhận dạng thông báo với hoạt động đang diễn ra để liên kết chúng với nhau.

Trạng thái

Status cho phép nhà phát triển hiển thị trạng thái trực tiếp hiện tại của OngoingActivity cho người dùng trên các khu vực mới, chẳng hạn như mục Recents (Gần đây) trong trình chạy. Để sử dụng tính năng này, hãy sử dụng Status.Builder.

Trong hầu hết trường hợp, nhà phát triển chỉ cần thêm một mẫu đại diện cho văn bản mà họ muốn xuất hiện trong mục Recents (Gần đây) của trình chạy ứng dụng.

Nhà phát triển có thể tuỳ chỉnh cách văn bản hiển thị với Spans bằng cách sử dụng phương thức addTemplate() và chỉ định bất kỳ phần động nào của văn bản dưới dạng Status.Part.

Ví dụ sau cho thấy cách làm cho từ "thời gian" xuất hiện với màu đỏ. Ví dụ này sử dụng Status.TimerPart cho phép chúng tôi biểu thị một đồng hồ hẹn giờ, hoặc Status.StopwatchPart để thể hiện đồng hồ bấm giờ trong mục Recents (Gần đây) của trình chạy ứng dụng.

Kotlin

val htmlStatus =
        "<p>The <font color=\"red\">time</font> on your current #type# is #time#.</p>"

val statusTemplate =
        Html.fromHtml(
                htmlStatus,
                Html.FROM_HTML_MODE_COMPACT
        )

// Creates a 5 minute timer.
// Note the use of SystemClock.elapsedRealtime(), not System.currentTimeMillis()
val runStartTime = SystemClock.elapsedRealtime() + TimeUnit.MINUTES.toMillis(5)

val status = new Status.Builder()
   .addTemplate(statusTemplate)
   .addPart("type", Status.TextPart("run"))
   .addPart("time", Status.StopwatchPart(runStartTime)
   .build()

Java

String htmlStatus =
        "<p>The <font color=\"red\">time</font> on your current #type# is #time#.</p>";

Spanned statusTemplate =
        Html.fromHtml(
                htmlStatus,
                Html.FROM_HTML_MODE_COMPACT
        );

// Creates a 5 minute timer.
// Note the use of SystemClock.elapsedRealtime(), not System.currentTimeMillis()
Long runStartTime = SystemClock.elapsedRealtime() + TimeUnit.MINUTES.toMillis(5);

Status status = new Status.Builder()
   .addTemplate(statusTemplate)
   .addPart("type", new Status.TextPart("run"))
   .addPart("time", new Status.StopwatchPart(runStartTime)
   .build();

Để tham chiếu một phần từ mẫu, hãy sử dụng tên được bao quanh bởi '#'. Để tạo '#' trong kết quả, hãy sử dụng '##' trong mẫu.

Ví dụ trước sử dụng HTMLCompat để tạo CharSequence giúp chuyển mẫu, điều này dễ dàng hơn so với việc xác định đối tượng Spannable theo cách thủ công.

Các tuỳ chỉnh Khác

Ngoài Status, nhà phát triển có thể tuỳ chỉnh hoạt động hoặc thông báo liên tục của họ theo các cách sau. Những tuỳ chỉnh này có thể được hoặc không được sử dụng dựa trên cách triển khai của OEM.

Thông báo hiển thị liên tục

  • Tập hợp danh mục xác định mức độ ưu tiên của hoạt động đang diễn ra.
    • CATEGORY_CALL: Cuộc gọi đến (gọi thoại hoặc gọi video) hoặc yêu cầu giao tiếp đồng bộ tương tự
    • CATEGORY_NAVIGATION: Bản đồ hoặc tính năng chỉ đường từng chặng.
    • CATEGORY_TRANSPORT: Trình điều khiển để phát nội dung chỉ đường
    • CATEGORY_ALARM: Chuông báo hoặc đồng hồ hẹn giờ
    • CATEGORY_WORKOUT: Bài tập thể dục (mới)
    • CATEGORY_LOCATION_SHARING: Chia sẻ vị trí tạm thời (mới)
    • CATEGORY_STOPWATCH: Đồng hồ bấm giờ (mới) \

Các hoạt động đang diễn ra

  • Biểu tượng động: Vectơ màu đen trắng, tốt nhất là có nền trong suốt. Hiển thị trên mặt đồng hồ ở chế độ đang hoạt động. Nếu bạn không đặt biểu tượng này thì hệ thống sẽ sử dụng biểu tượng thông báo mặc định.

  • Biểu tượng tĩnh: Biểu tượng vectơ có nền trong suốt. Hiển thị trên mặt đồng hồ ở chế độ môi trường xung quanh. Nếu bạn không đặt biểu tượng động, thì biểu tượng tĩnh sẽ được dùng trên mặt đồng hồ cho chế độ đang hoạt động. Nếu bạn không đặt biểu tượng này thì hệ thống sẽ sử dụng biểu tượng thông báo. Nếu bạn không đặt biểu tượng nào thì hệ thống sẽ gửi một trường hợp ngoại lệ. (Biểu tượng dùng trong trình chạy ứng dụng vẫn sẽ là biểu tượng ứng dụng.)

  • OngoingActivityStatus (Trạng thái hoạt động đang diễn ra): Văn bản thuần tuý hoặc Chronometer. Hiển thị trong mục Recents (Gần đây) của trình chạy ứng dụng. Hệ thống sẽ sử dụng thông báo bằng “văn bản theo ngữ cảnh” nếu trạng thái không được cung cấp.

  • Ý định nhấn: PendingIntent dùng để chuyển trở lại ứng dụng nếu người dùng nhấn vào biểu tượng hoạt động đang diễn ra. Hiển thị trên mặt đồng hồ hoặc trên mục trình chạy. Ý định này có thể khác với ý định ban đầu dùng để chạy ứng dụng. Nếu không được cung cấp, hệ thống sẽ sử dụng ý định nội dung của thông báo, nếu không có ý định nào được đặt, thì hệ thống sẽ gửi một trường hợp ngoại lệ. \

  • LocusId: Mã nhận dạng chỉ định lối tắt của trình chạy tương ứng với hoạt động đang diễn ra. Hiển thị trên trình chạy ở mục Recents (Gần đây) trong khi hoạt động đang diễn ra. Nếu mã không được cung cấp, trình chạy sẽ ẩn tất cả các mục của ứng dụng trong phần Recents (Gần đây) khỏi gói chung và chỉ hiển thị hoạt động đang diễn ra. \

  • Mã nhận dạng hoạt động đang diễn ra (Ongoing Activity ID) là mã được dùng để phân biệt các lệnh gọi tới fromExistingOngoingActivityfromExistingOngoingActivity() khi một ứng dụng có nhiều hoạt động đang diễn ra.

Cập nhật một hoạt động đang diễn ra

Trong hầu hết các trường hợp, nhà phát triển sẽ tạo một thông báo mới hiển thị liên tục và một hoạt động mới đang diễn ra khi họ cần cập nhật dữ liệu trên màn hình. Tuy nhiên, API Ongoing Activity (hoạt động đang diễn ra) cũng cung cấp các phương thức trợ giúp để cập nhật OngoingActivity nếu bạn muốn giữ lại một thực thể thay vì tạo lại thực thể đó.

Nếu đang chạy ở chế độ nền thì ứng dụng có thể gửi các bản cập nhật cho API Ongoing Activity (hoạt động đang diễn ra), nhưng điều này sẽ không thường xuyên. Phương thức cập nhật có thể bỏ qua các lệnh gọi quá gần nhau. Mỗi phút một vài bản cập nhật là hợp lý.

Để cập nhật hoạt động đang diễn ra và thông báo đã đăng, hãy sử dụng đối tượng mà bạn đã tạo trước đó rồi gọi update() như trong ví dụ sau:

Kotlin

ongoingActivity.update(context, newStatus)

Java

ongoingActivity.update(context, newStatus);

Để thuận tiện, có một phương thức tĩnh mà bạn có thể dùng để tạo hoạt động đang diễn ra.

Kotlin

OngoingActivity.recoverOngoingActivity(context)
               .update(context, newStatus)

Java

OngoingActivity.recoverOngoingActivity(context)
               .update(context, newStatus);

Dừng một hoạt động đang diễn ra

Khi ứng dụng hoàn tất việc chạy dưới dạng một hoạt động đang diễn ra, ứng dụng chỉ cần huỷ thông báo hiển thị liên tục.

Ứng dụng có quyền huỷ thông báo hiển thị liên tục hoặc hoạt động đang diễn ra khi chạy trên nền trước, sau đó tạo lại các thông báo hoặc hoạt động này khi quay lại chế độ nền.

Tạm dừng một hoạt động đang diễn ra

Nếu ứng dụng của bạn dừng một cách rõ ràng, hãy tiếp tục hoạt động đang diễn ra sau khi ứng dụng chạy trở lại. Tuy nhiên, các ứng dụng không dừng một cách rõ ràng sẽ kết thúc hoạt động (đang diễn ra) khi bị tạm dừng.

Các phương pháp hay nhất

Hãy nhớ những điều sau khi làm việc với API Ongoing Activity (hoạt động đang diễn ra):

  • Luôn gọi ongoingActivity.apply(context) trước khi gọi notificationManager.notify(...).
  • Luôn đặt biểu tượng tĩnh cho Hoạt động đang diễn ra của bạn một cách rõ ràng hoặc đặt dưới dạng trường hợp dự phòng thông qua thông báo. Nếu không, bạn sẽ nhận được một IllegalArgumentException.

  • Biểu tượng phải là các vectơ đen trắng có nền trong suốt.

  • Luôn đặt ý định nhấn cho hoạt động đang diễn ra của bạn một cách rõ ràng hoặc dưới dạng trường hợp dự phòng bằng cách sử dụng thông báo. Nếu không, bạn sẽ nhận được một IllegalArgumentException.

  • Đối với NotificationCompat, hãy sử dụng thư viện androidx cốt lõi core:1.5.0-alpha05+, bao gồm LocusIdCompatcác danh mục mới (bài tập thể dục, đồng hồ bấm giờ hoặc chia sẻ vị trí).

  • Nếu ứng dụng của bạn có nhiều hoạt động MAIN LAUNCHER được khai báo trong tệp kê khai, hãy phát hành một lối tắt động và liên kết lối tắt này với hoạt động đang diễn ra bằng cách sử dụng LocusId