Tạo ứng dụng trình duyệt đa phương tiện

Để hoàn tất thiết kế ứng dụng/máy chủ, bạn phải tạo một thành phần hoạt động chứa mã giao diện người dùng, một MediaController được liên kết và một MediaBrowser.

MediaBrowser thực hiện hai chức năng quan trọng: Trình duyệt này kết nối với MediaBrowserService và khi kết nối sẽ tạo MediaController cho giao diện người dùng của bạn.

Lưu ý: Bạn nên triển khai MediaBrowser là MediaBrowserCompat, được xác định trong thư viện hỗ trợ Media-Compat. Trong suốt trang này, thuật ngữ "MediaBrowser" đề cập đến một thực thể của MediaBrowserCompat.

Kết nối với MediaBrowserService

Khi hoạt động của ứng dụng được tạo, hoạt động đó sẽ kết nối với MediaBrowserService. Tôi có một vài cái bắt tay và một điệu nhảy. Sửa đổi các phương thức gọi lại trong vòng đời của hoạt động như sau:

  • onCreate() tạo MediaBrowserCompat. Truyền tên của MediaBrowserService và MediaBrowserCompat.ConnectionCallback mà bạn đã xác định.
  • onStart() kết nối với MediaBrowserService. Đây chính là lúc sự kỳ diệu của MediaBrowserCompat.ConnectionCallback phát huy tác dụng. Nếu kết nối thành công, lệnh gọi lại onConnect() sẽ tạo trình điều khiển nội dung đa phương tiện, liên kết trình điều khiển đó với phiên phát nội dung đa phương tiện, liên kết các chế độ điều khiển trên giao diện người dùng của bạn với MediaController và đăng ký trình điều khiển để nhận lệnh gọi lại từ phiên phát nội dung đa phương tiện.
  • onResume() thiết lập luồng âm thanh để ứng dụng của bạn phản hồi chế độ điều chỉnh âm lượng trên thiết bị.
  • onStop() sẽ ngắt kết nối MediaBrowser và huỷ đăng ký MediaController.Callback khi hoạt động của bạn dừng.

Kotlin

class MediaPlayerActivity : AppCompatActivity() {

    private lateinit var mediaBrowser: MediaBrowserCompat

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        // Create MediaBrowserServiceCompat
        mediaBrowser = MediaBrowserCompat(
                this,
                ComponentName(this, MediaPlaybackService::class.java),
                connectionCallbacks,
                null // optional Bundle
        )
    }

    public override fun onStart() {
        super.onStart()
        mediaBrowser.connect()
    }

    public override fun onResume() {
        super.onResume()
        volumeControlStream = AudioManager.STREAM_MUSIC
    }

    public override fun onStop() {
        super.onStop()
        // (see "stay in sync with the MediaSession")
        MediaControllerCompat.getMediaController(this)?.unregisterCallback(controllerCallback)
        mediaBrowser.disconnect()
    }
}

Java

public class MediaPlayerActivity extends AppCompatActivity {
  private MediaBrowserCompat mediaBrowser;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...
    // Create MediaBrowserServiceCompat
    mediaBrowser = new MediaBrowserCompat(this,
      new ComponentName(this, MediaPlaybackService.class),
        connectionCallbacks,
        null); // optional Bundle
  }

  @Override
  public void onStart() {
    super.onStart();
    mediaBrowser.connect();
  }

  @Override
  public void onResume() {
    super.onResume();
    setVolumeControlStream(AudioManager.STREAM_MUSIC);
  }

  @Override
  public void onStop() {
    super.onStop();
    // (see "stay in sync with the MediaSession")
    if (MediaControllerCompat.getMediaController(MediaPlayerActivity.this) != null) {
      MediaControllerCompat.getMediaController(MediaPlayerActivity.this).unregisterCallback(controllerCallback);
    }
    mediaBrowser.disconnect();

  }
}

Tuỳ chỉnh MediaBrowserCompat.ConnectionCallback

Khi hoạt động của bạn tạo MediaBrowserCompat, bạn phải tạo một thực thể của ConnectionCallback. Sửa đổi phương thức onConnected() để truy xuất mã phiên phát nội dung đa phương tiện từ MediaBrowserService và sử dụng mã thông báo này để tạo MediaControllerCompat.

Sử dụng phương thức tiện lợi MediaControllerCompat.setMediaController() để lưu đường liên kết vào tay điều khiển. Trường này cho phép xử lý các nút nội dung đa phương tiện. API này cũng cho phép bạn gọi MediaControllerCompat.getMediaController() để truy xuất bộ điều khiển khi tạo bộ điều khiển truyền tải.

Mã mẫu sau đây cho biết cách sửa đổi phương thức onConnected().

Kotlin

private val connectionCallbacks = object : MediaBrowserCompat.ConnectionCallback() {
    override fun onConnected() {

        // Get the token for the MediaSession
        mediaBrowser.sessionToken.also { token ->

            // Create a MediaControllerCompat
            val mediaController = MediaControllerCompat(
                    this@MediaPlayerActivity, // Context
                    token
            )

            // Save the controller
            MediaControllerCompat.setMediaController(this@MediaPlayerActivity, mediaController)
        }

        // Finish building the UI
        buildTransportControls()
    }

    override fun onConnectionSuspended() {
        // The Service has crashed. Disable transport controls until it automatically reconnects
    }

    override fun onConnectionFailed() {
        // The Service has refused our connection
    }
}

Java

private final MediaBrowserCompat.ConnectionCallback connectionCallbacks =
  new MediaBrowserCompat.ConnectionCallback() {
    @Override
    public void onConnected() {

      // Get the token for the MediaSession
      MediaSessionCompat.Token token = mediaBrowser.getSessionToken();

      // Create a MediaControllerCompat
      MediaControllerCompat mediaController =
        new MediaControllerCompat(MediaPlayerActivity.this, // Context
        token);

      // Save the controller
      MediaControllerCompat.setMediaController(MediaPlayerActivity.this, mediaController);

      // Finish building the UI
      buildTransportControls();
    }

    @Override
    public void onConnectionSuspended() {
      // The Service has crashed. Disable transport controls until it automatically reconnects
    }

    @Override
    public void onConnectionFailed() {
      // The Service has refused our connection
    }
  };

Kết nối giao diện người dùng với trình điều khiển nội dung nghe nhìn

Trong mã mẫu ConnectionCallback ở trên, hãy đưa lệnh gọi đến buildTransportControls() để hoàn thiện giao diện người dùng của bạn. Bạn cần đặt onClickListener cho các phần tử trên giao diện người dùng điều khiển trình phát. Chọn phương thức MediaControllerCompat.TransportControls thích hợp cho từng phương thức.

Mã của bạn sẽ trông giống như sau, với một onClickListener cho mỗi nút:

Kotlin

fun buildTransportControls() {
    val mediaController = MediaControllerCompat.getMediaController(this@MediaPlayerActivity)
    // Grab the view for the play/pause button
    playPause = findViewById<ImageView>(R.id.play_pause).apply {
        setOnClickListener {
            // Since this is a play/pause button, you'll need to test the current state
            // and choose the action accordingly

            val pbState = mediaController.playbackState.state
            if (pbState == PlaybackStateCompat.STATE_PLAYING) {
                mediaController.transportControls.pause()
            } else {
                mediaController.transportControls.play()
            }
        }
    }

    // Display the initial state
    val metadata = mediaController.metadata
    val pbState = mediaController.playbackState

    // Register a Callback to stay in sync
    mediaController.registerCallback(controllerCallback)
}

Java

void buildTransportControls()
{
  // Grab the view for the play/pause button
  playPause = (ImageView) findViewById(R.id.play_pause);

  // Attach a listener to the button
  playPause.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
      // Since this is a play/pause button, you'll need to test the current state
      // and choose the action accordingly

      int pbState = MediaControllerCompat.getMediaController(MediaPlayerActivity.this).getPlaybackState().getState();
      if (pbState == PlaybackStateCompat.STATE_PLAYING) {
        MediaControllerCompat.getMediaController(MediaPlayerActivity.this).getTransportControls().pause();
      } else {
        MediaControllerCompat.getMediaController(MediaPlayerActivity.this).getTransportControls().play();
      }
  });

  MediaControllerCompat mediaController = MediaControllerCompat.getMediaController(MediaPlayerActivity.this);

  // Display the initial state
  MediaMetadataCompat metadata = mediaController.getMetadata();
  PlaybackStateCompat pbState = mediaController.getPlaybackState();

  // Register a Callback to stay in sync
  mediaController.registerCallback(controllerCallback);
}
}

Các phương thức TransportControls sẽ gửi lệnh gọi lại đến phiên phát nội dung đa phương tiện của dịch vụ. Hãy đảm bảo rằng bạn đã xác định phương thức MediaSessionCompat.Callback tương ứng cho từng chế độ điều khiển.

Đồng bộ hoá phiên phát nội dung đa phương tiện

Giao diện người dùng phải hiển thị trạng thái hiện tại của phiên phát nội dung đa phương tiện, như được mô tả trong PlaybackState và Siêu dữ liệu. Khi tạo các chế độ điều khiển truyền tải, bạn có thể lấy trạng thái hiện tại của phiên hoạt động, hiển thị trạng thái đó trong giao diện người dùng, cũng như bật và tắt các chế độ điều khiển truyền tải dựa trên trạng thái và các thao tác hiện có.

Để nhận lệnh gọi lại từ phiên phát nội dung đa phương tiện mỗi khi trạng thái hoặc siêu dữ liệu của phiên đó thay đổi, hãy xác định MediaControllerCompat.Callback bằng 2 phương thức sau:

Kotlin

private var controllerCallback = object : MediaControllerCompat.Callback() {

    override fun onMetadataChanged(metadata: MediaMetadataCompat?) {}

    override fun onPlaybackStateChanged(state: PlaybackStateCompat?) {}
}

Java

MediaControllerCompat.Callback controllerCallback =
  new MediaControllerCompat.Callback() {
    @Override
    public void onMetadataChanged(MediaMetadataCompat metadata) {}

    @Override
    public void onPlaybackStateChanged(PlaybackStateCompat state) {}
  };

Đăng ký lệnh gọi lại khi bạn tạo các điều khiển truyền tải (xem phương thức buildTransportControls()) và huỷ đăng ký khi hoạt động ngừng hoạt động (trong phương thức vòng đời onStop() của hoạt động).

Ngắt kết nối khi phiên phát nội dung đa phương tiện bị huỷ

Nếu phiên phát nội dung đa phương tiện không hợp lệ, lệnh gọi lại onSessionDestroyed() sẽ được đưa ra. Khi điều đó xảy ra, phiên đó không thể hoạt động trở lại trong vòng đời của MediaBrowserService. Mặc dù các hàm liên quan đến MediaBrowser có thể tiếp tục hoạt động, nhưng người dùng không thể xem hoặc kiểm soát việc phát từ một phiên nội dung nghe nhìn bị huỷ bỏ. Điều này có thể làm giảm giá trị của ứng dụng.

Do đó, khi phiên bị huỷ, bạn phải ngắt kết nối khỏi MediaBrowserService bằng cách gọi disconnect(). Điều này đảm bảo dịch vụ trình duyệt không có ứng dụng liên kết và hệ điều hành có thể huỷ. Nếu sau này bạn cần kết nối lại với MediaBrowserService (ví dụ: nếu ứng dụng của bạn muốn duy trì kết nối liên tục với ứng dụng đa phương tiện), hãy tạo một thực thể MediaBrowser mới thay vì sử dụng lại thực thể cũ.

Đoạn mã sau đây minh hoạ cách triển khai lệnh gọi lại ngắt kết nối khỏi dịch vụ trình duyệt khi phiên phát nội dung đa phương tiện bị huỷ:

Kotlin

private var controllerCallback = object : MediaControllerCompat.Callback() {
    override fun onSessionDestroyed() {
      mediaBrowser.disconnect()
      // maybe schedule a reconnection using a new MediaBrowser instance
    }
}

Java

MediaControllerCompat.Callback controllerCallback =
  new MediaControllerCompat.Callback() {
    @Override
    public void onSessionDestroyed() {
      mediaBrowser.disconnect();
      // maybe schedule a reconnection using a new MediaBrowser instance
    }
  };