미디어 브라우저 클라이언트 빌드

클라이언트/서버 디자인을 완료하려면 UI 코드, 연결된 MediaController 및 MediaBrowser를 포함하는 활동 구성요소를 빌드해야 합니다.

MediaBrowser에는 두 가지 중요한 기능이 있는데, 하나는 MediaBrowserService에 연결하는 것이고 다른 하나는 연결 이후 UI의 MediaController를 만드는 것입니다.

참고: MediaBrowser의 권장되는 구현은 MediaBrowserCompat, 이는 Media-Compat 지원 라이브러리입니다. 이 페이지 전체에서 '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()
    }
}

자바

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
    }
}

자바

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)
}

자바

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?) {}
}

자바

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

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

전송 컨트롤을 빌드할 때 콜백을 등록하고(buildTransportControls() 메서드 참조) 활동이 중지될 때 등록을 취소합니다(활동의 onStop() 수명 주기 메서드에서).

미디어 세션 소멸 시 연결 해제

미디어 세션이 무효가 되면 onSessionDestroyed() 드림 콜백이 호출되면 이 경우 세션이 기능할 수 없습니다. MediaBrowserService의 전체 기간 내에 다시 호출됩니다. 함수는 MediaBrowser 관련 기능은 계속 작동할 수 있지만, 사용자는 보거나 제어할 수 없습니다. 재생 중이 아니기 때문에 손실된 미디어 세션의 가치는 실행할 수 있습니다

따라서 세션이 소멸되면 반드시 다음을 호출하여 MediaBrowserService disconnect() 이렇게 하면 브라우저 서비스에 바인딩된 클라이언트가 없으며 인터페이스로 인해 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
    }
  };