Phản hồi các nút đa phương tiện

Nút nội dung đa phương tiện là các nút phần cứng có trên thiết bị Android và các thiết bị ngoại vi khác, chẳng hạn như nút tạm dừng/phát trên tai nghe Bluetooth. Khi người dùng nhấn vào một nút đa phương tiện, Android sẽ tạo một KeyEvent chứa mã phím xác định nút đó. Mã phím cho KeyEvents của nút đa phương tiện là các hằng số bắt đầu bằng KEYCODE_MEDIA (ví dụ: KEYCODE_MEDIA_PLAY).

Ứng dụng có thể xử lý các sự kiện nút đa phương tiện trong ba trường hợp, theo thứ tự sau mức độ ưu tiên:

  • Khi hoạt động trên giao diện người dùng của ứng dụng hiển thị
  • Khi hoạt động trên giao diện người dùng bị ẩn và phiên phát nội dung nghe nhìn của ứng dụng đang hoạt động
  • Khi hoạt động trên giao diện người dùng bị ẩn và phiên đa phương tiện của ứng dụng không hoạt động và cần được khởi động lại

Xử lý các nút đa phương tiện trong hoạt động trên nền trước

Hoạt động trên nền trước nhận sự kiện chính của nút đa phương tiện trong onKeyDown() . Tuỳ thuộc vào phiên bản Android đang chạy, hệ thống có 2 cách để chuyển sự kiện đến trình điều khiển nội dung nghe nhìn:

  • Nếu bạn đang chạy Android 5.0 (API cấp 21) trở lên, hãy gọi FLAG_HANDLES_MEDIA_BUTTONS MediaBrowserCompat.ConnectionCallback.onConnected Thao tác này sẽ tự động gọi dispatchMediaButtonEvent(), lệnh này sẽ dịch mã phím sang lệnh gọi lại phiên đa phương tiện.
  • Trước Android 5.0 (API cấp 21), bạn cần sửa đổi onKeyDown() để xử lý sự kiện đó. (Xem bài viết Xử lý các nút đa phương tiện trong một phiên phát nội dung nghe nhìn đang hoạt động để biết thông tin chi tiết.) Đoạn mã sau đây cho biết cách chặn mã khoá và gọi dispatchMediaButtonEvent(). Hãy nhớ trả lại true để cho biết rằng sự kiện đã được xử lý:

    Kotlin

        fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                return super.onKeyDown(keyCode, event)
            }
            when (keyCode) {
                KeyEvent.KEYCODE_MEDIA_PLAY -> {
                    yourMediaController.dispatchMediaButtonEvent(event)
                    return true
                }
            }
            return super.onKeyDown(keyCode, event)
        }
        

    Java

        @Override
        boolean onKeyDown(int keyCode, KeyEvent event) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                  return super.onKeyDown(keyCode, event);
                }
                switch (keyCode) {
                  case KeyEvent.KEYCODE_MEDIA_PLAY:
                          yourMediaController.dispatchMediaButtonEvent(event);
                          return true;
                }
                return super.onKeyDown(keyCode, event);
        }
        

Tìm một phiên phát nội dung nghe nhìn

Nếu hoạt động trên nền trước không xử lý sự kiện, Android sẽ cố gắng tìm một có thể xử lý nó. Một lần nữa, tuỳ thuộc vào phiên bản đang chạy của Trên Android, có 2 cách để tìm kiếm một phiên phát nội dung đa phương tiện:

  • Nếu bạn đang chạy Android 8.0 (API cấp 26) trở lên, hệ thống sẽ cố gắng tìm ứng dụng cuối cùng có MediaSession phát âm thanh trên thiết bị. Nếu phiên hoạt động vẫn đang hoạt động. Android sẽ gửi trực tiếp sự kiện đến ứng dụng đó. Ngược lại, nếu phiên hoạt động không hoạt động và có bộ nhận mediabutton, Android sẽ gửi sự kiện đến trình nhận, trình nhận này sẽ khởi động lại phiên và để có thể nhận được sự kiện. (Xem bài viết Sử dụng các nút đa phương tiện để bắt đầu lại phiên phát nội dung nghe nhìn không hoạt động để biết thông tin chi tiết.) Nếu phiên không có bộ nhận nút nội dung nghe nhìn, hệ thống sẽ loại bỏ nội dung nghe nhìn và sẽ không có gì xảy ra. Logic này được thể hiện như sau sơ đồ:

  • Trước Android 8.0 (API cấp 26), hệ thống sẽ cố gắng gửi sự kiện đến một phiên phát nội dung nghe nhìn đang hoạt động. Nếu có nhiều phiên phát nội dung nghe nhìn đang hoạt động, Android sẽ cố gắng để chọn phiên đa phương tiện đang chuẩn bị phát (lưu vào bộ đệm/kết nối), đang phát hoặc tạm dừng, thay vì một video bị dừng. (Xem Xử lý các nút đa phương tiện trong một phiên phát nội dung nghe nhìn đang hoạt động để biết thêm chi tiết.) Nếu không có mã nào đang hoạt động Android sẽ cố gắng gửi sự kiện này đến phiên hoạt động gần đây nhất. (Xem bài viết Sử dụng các nút đa phương tiện để bắt đầu lại phiên phát nội dung nghe nhìn không hoạt động để biết thông tin chi tiết.) Logic này được thể hiện trong sơ đồ sau:

Xử lý các nút nội dung nghe nhìn trong một phiên nội dung nghe nhìn đang hoạt động

Trên Android 5.0 (API cấp 21) trở lên, Android sẽ tự động gửi các sự kiện nút đa phương tiện đến phiên phát nội dung đa phương tiện đang hoạt động bằng cách gọi onMediaButtonEvent(). Theo mặc định, lệnh gọi lại này sẽ dịch KeyEvent thành phương thức Gọi lại phiên phát nội dung nghe nhìn thích hợp khớp với mã phím.

Trước Android 5.0 (API cấp 21), Android xử lý các sự kiện nút đa phương tiện bằng cách truyền một ý định bằng thao tác ACTION_MEDIA_BUTTON. Ứng dụng của bạn phải đăng ký BroadcastReceiver để chặn các ý định này. Chiến lược phát hành đĩa đơn MediaButtonReceiver được thiết kế dành riêng cho cho mục đích này. Đó là một lớp tiện lợi trong Android media-compat và xử lý ACTION_MEDIA_BUTTON và chuyển Ý định đến thành lệnh gọi phương thức MediaSessionCompat.Callback thích hợp.

MediaButtonReceiver là một BroadcastReceiver tồn tại trong thời gian ngắn. Nó chuyển tiếp cuộc gọi đến ý định đối với dịch vụ đang quản lý phiên phát nội dung đa phương tiện của bạn. Nếu bạn muốn sử dụng các nút đa phương tiện trong các hệ thống trước phiên bản Android 5.0, bạn phải đưa vào MediaButtonReceiver trong tệp kê khai của bạn bằng bộ lọc ý định MEDIA_BUTTON.:

<receiver android:name="android.support.v4.media.session.MediaButtonReceiver" >
   <intent-filter>
     <action android:name="android.intent.action.MEDIA_BUTTON" />
   </intent-filter>
 </receiver>

BroadcastReceiver chuyển tiếp ý định đến dịch vụ của bạn. Để phân tích cú pháp ý định và tạo lệnh gọi lại cho phiên phát nội dung đa phương tiện, hãy đưa phương thức MediaButtonReceiver.handleIntent() vào onStartCommand() của dịch vụ. Thao tác này sẽ dịch mã khoá thành phương thức gọi lại phiên thích hợp.

Kotlin

private val mediaSessionCompat: MediaSessionCompat = ...

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    MediaButtonReceiver.handleIntent(mediaSessionCompat, intent)
    return super.onStartCommand(intent, flags, startId)
}

Java

private MediaSessionCompat mediaSessionCompat = ...;

 public int onStartCommand(Intent intent, int flags, int startId) {
   MediaButtonReceiver.handleIntent(mediaSessionCompat, intent);
   return super.onStartCommand(intent, flags, startId);
 }

Sử dụng các nút nội dung nghe nhìn để khởi động lại phiên phát nội dung nghe nhìn không hoạt động

Nếu có thể xác định phiên phát nội dung đa phương tiện hoạt động gần đây nhất, thì Android sẽ cố gắng khởi động lại phiên đó bằng cách gửi một Ý định ACTION_MEDIA_BUTTON đến một thành phần đã đăng ký tệp kê khai (chẳng hạn như một dịch vụ hoặc BroadcastReceiver).

Việc này cho phép ứng dụng bắt đầu lại quá trình phát trong khi giao diện người dùng của ứng dụng không hiển thị, trường hợp này xảy ra với hầu hết các ứng dụng âm thanh.

Hành vi này được tự động bật khi bạn sử dụng MediaSessionCompat. Nếu bạn sử dụng MediaSession của khung Android hoặc Thư viện hỗ trợ 24.0.0 cho đến 25.1.1 Bạn phải gọi setMediaButtonReceiver để cho phép nút đa phương tiện khởi động lại phiên phát nội dung nghe nhìn không hoạt động.

Bạn có thể vô hiệu hoá hành vi này trong Android 5.0 (API cấp 21) trở lên bằng cách đặt bộ nhận nút đa phương tiện rỗng:

Kotlin

// Create a MediaSessionCompat
mediaSession = MediaSessionCompat(context, LOG_TAG)
mediaSession.setMediaButtonReceiver(null)

Java

// Create a MediaSessionCompat
mediaSession = new MediaSessionCompat(context, LOG_TAG);
mediaSession.setMediaButtonReceiver(null);

Tuỳ chỉnh trình xử lý nút đa phương tiện

Hành vi mặc định của onMediaButtonEvent() trích xuất mã phím và sử dụng trạng thái hiện tại của phiên phát nội dung đa phương tiện cũng như danh sách các thao tác được hỗ trợ để xác định phương thức cần gọi. Ví dụ: KEYCODE_MEDIA_PLAY gọi onPlay().

Để mang đến trải nghiệm nhất quán khi dùng nút đa phương tiện trên tất cả ứng dụng, bạn nên dùng hành vi mặc định và chỉ đi chệch cho một mục đích cụ thể. Nếu một nút nội dung nghe nhìn cần xử lý tuỳ chỉnh, hãy ghi đè lệnh gọi lại onMediaButtonEvent() hãy trích xuất KeyEvent bằng cách sử dụng intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT), tự xử lý sự kiện đó rồi trả về true.

Tóm tắt

Để xử lý đúng cách các sự kiện nút đa phương tiện trong tất cả phiên bản Android, bạn phải chỉ định FLAG_HANDLES_MEDIA_BUTTONS khi bạn tạo một phiên phát nội dung nghe nhìn.

Ngoài ra, tuỳ thuộc vào phiên bản Android mà bạn định hỗ trợ, bạn cũng phải đáp ứng các yêu cầu sau:

Khi chạy trong Android 5.0 trở lên:

  • Gọi MediaControllerCompat.setMediaController() từ lệnh gọi lại onConnected() của trình điều khiển nội dung nghe nhìn
  • Để cho phép một nút nội dung đa phương tiện khởi động lại một phiên không hoạt động, hãy tự động tạo một MediaButtonReceiver bằng cách gọi setMediaButtonReceiver() và truyền cho nó một PendingIntent

Khi chạy trong các hệ thống cũ hơn Android 5.0:

  • Ghi đè onKeyDown() của hoạt động để xử lý các nút đa phương tiện
  • Tạo tĩnh một MediaButtonReceiver bằng cách thêm mã này vào tệp kê khai của ứng dụng