클라이언트/서버 디자인을 완료하려면 UI 코드, 연결된 MediaController 및 MediaBrowser를 포함하는 활동 구성요소를 빌드해야 합니다.
MediaBrowser에는 두 가지 중요한 기능이 있는데, 하나는 MediaBrowserService에 연결하는 것이고 다른 하나는 연결 이후 UI의 MediaController를 만드는 것입니다.
참고: MediaBrowser의 권장 구현은 Media-Compat 지원 라이브러리에 정의된 MediaBrowserCompat
입니다.
이 페이지에서 'MediaBrowser'라는 용어는 MediaBrowserCompat의 인스턴스를 의미합니다.
MediaBrowserService에 연결
클라이언트 활동이 생성되면 MediaBrowserService에 연결됩니다. 약간의 동작이 관련되어 있습니다. 활동의 수명 주기 콜백을 다음과 같이 수정합니다.
onCreate()
는 MediaBrowserCompat를 생성합니다. 정의한 MediaBrowserService 및 MediaBrowserCompat.ConnectionCallback의 이름을 전달하세요.onStart()
는 MediaBrowserService에 연결합니다. 여기에서 MediaBrowserCompat.ConnectionCallback이 작동합니다. 연결되면 onConnect() 콜백이 미디어 컨트롤러를 만들어 미디어 세션에 연결하고 UI 컨트롤을 MediaController에 연결하며 컨트롤러를 등록하여 미디어 세션에서 콜백을 수신합니다.onResume()
은 앱이 기기의 볼륨 컨트롤에 응답하도록 오디오 스트림을 설정합니다.onStop()
은 활동이 중지될 때 MediaBrowser의 연결을 해제하고 MediaController.Callback의 등록을 취소합니다.
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(); } }
MediaBrowserCompat.ConnectionCallback 맞춤 설정
활동에서 MediaBrowserCompat가 생성되면 ConnectionCallback의 인스턴스를 만들어야 합니다. MediaBrowserService에서 미디어 세션 토큰을 검색하고 토큰을 사용하여 MediaControllerCompat를 만들려면 onConnected()
메서드를 수정합니다.
편의 메서드 MediaControllerCompat.setMediaController()
를 사용하여 컨트롤러의 링크를 저장합니다. 그러면 미디어 버튼을 처리할 수 있습니다. 또한 전송 컨트롤을 빌드할 때 MediaControllerCompat.getMediaController()
를 호출하여 컨트롤러를 검색할 수도 있습니다.
다음 코드 샘플은 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 } };
미디어 컨트롤러에 UI 연결
위의 ConnectionCallback 샘플 코드에는 UI를 구체화하기 위한 buildTransportControls()
호출이 포함되어 있습니다. 플레이어를 제어하는 UI 요소의 onClickListeners를 설정해야 합니다. 각각에 적절한 MediaControllerCompat.TransportControls
메서드를 선택합니다.
코드는 다음과 같으며 각 버튼에 onClickListener가 있습니다.
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); } }
TransportControls 메서드는 서비스의 미디어 세션에 콜백을 보냅니다. 각 컨트롤에 상응하는 MediaSessionCompat.Callback
메서드를 정의했는지 확인하세요.
미디어 세션과 동기화 유지
UI는 PlaybackState 및 Metadata에서 설명한 대로 미디어 세션의 현재 상태를 표시해야 합니다. 전송 컨트롤을 만들면 세션의 현재 상태를 가져와 UI에 표시하고, 상태 및 사용 가능한 작업에 따라 전송 컨트롤을 사용 설정 또는 사용 중지할 수 있습니다.
상태 또는 메타데이터가 변경될 때마다 미디어 세션에서 콜백을 수신하려면 다음 두 가지 메서드를 사용하여 MediaControllerCompat.Callback
를 정의합니다.
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) {} };
전송 컨트롤을 빌드할 때 콜백을 등록하고(buildTransportControls()
메서드 참조) 활동이 중지될 때 등록을 취소합니다(활동의 onStop()
수명 주기 메서드에서).
미디어 세션이 소멸될 때 연결 해제
미디어 세션이 무효화되면 onSessionDestroyed()
콜백이 실행됩니다. 이 경우 세션이 MediaBrowserService
의 전체 기간 내에 다시 작동할 수 없습니다. MediaBrowser
관련 기능이 계속 작동할 수도 있지만 사용자가 삭제된 미디어 세션에서 재생을 보거나 제어할 수 없으므로 애플리케이션의 가치가 감소할 수 있습니다.
따라서 세션이 소멸되면 반드시 disconnect()
를 호출하여 MediaBrowserService
에서 연결을 해제해야 합니다.
이렇게 하면 브라우저 서비스에 바인드된 클라이언트가 없고 OS에 의해 폐기될 수 있습니다.
나중에 MediaBrowserService
에 다시 연결해야 하는 경우 (예: 애플리케이션이 미디어 앱의 영구 연결을 유지하려는 경우) 이전 인스턴스를 재사용하지 말고 MediaBrowser
의 새 인스턴스를 만드세요.
다음 코드 스니펫은 미디어 세션이 제거될 때 브라우저 서비스에서 연결 해제되는 콜백 구현을 보여줍니다.
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 } };