미디어 컨트롤러는 미디어 세션과 상호작용하여 미디어 앱의 재생을 쿼리하고 제어합니다. Media3에서 MediaController
API는 Player
인터페이스를 구현합니다. 미디어 컨트롤러를 사용하는 클라이언트 앱의 예는 다음과 같습니다.
- Android 시스템 미디어 컨트롤
- Android Wear OS 호환 앱
- Android Auto 및 Automotive OS
- Google 어시스턴트와 같은 음성 어시스턴트
- 미디어 컨트롤러 테스트 앱
미디어 컨트롤러는 미디어 앱 내에서도 유용할 수 있습니다. 예를 들어 플레이어와 미디어 세션이 UI가 있는 Activity
또는 Fragment
와 별도의 Service
에 있는 경우입니다.
MediaController
를 만드는 방법
MediaController
을 만들려면 먼저 상응하는 MediaSession
의 SessionToken
를 만듭니다. Activity
또는 Fragment
의 onStart()
메서드가 적합합니다.
Kotlin
val sessionToken =
SessionToken(context, ComponentName(context, PlaybackService::class.java))
자바
SessionToken sessionToken =
new SessionToken(context, new ComponentName(context, PlaybackService.class));
이 SessionToken
를 사용하여 MediaController
를 빌드하면 컨트롤러가 지정된 세션에 연결됩니다. 이는 비동기식으로 실행되므로 결과를 리슨하고 사용 가능한 경우 사용해야 합니다.
Kotlin
val controllerFuture =
MediaController.Builder(context, sessionToken).buildAsync()
controllerFuture.addListener({
// MediaController is available here with controllerFuture.get()
}, MoreExecutors.directExecutor())
자바
ListenableFuture<MediaController> controllerFuture =
new MediaController.Builder(context, sessionToken).buildAsync();
controllerFuture.addListener(() -> {
// MediaController is available here with controllerFuture.get()
}, MoreExecutors.directExecutor());
MediaController
사용
MediaController
는 Player
인터페이스를 구현하므로 인터페이스에 정의된 명령어를 사용하여 연결된 MediaSession
의 재생을 제어할 수 있습니다.
즉, MediaController
에서 play()
를 호출하면 연결된 MediaSession
에 명령어가 전송되고 MediaSession
는 이후에 기본 Player
에 명령어를 위임합니다.
컨트롤러에 Player.Listener
를 추가하여 Player
상태의 변경사항을 수신 대기할 수 있습니다. Player.Listener
사용에 관한 자세한 내용은 플레이어 이벤트 가이드를 참고하세요.
MediaController.Listener
인터페이스는 연결된 MediaSession
의 이벤트 및 맞춤 명령어에 관한 추가 콜백을 정의합니다. 예를 들어 세션에서 맞춤 명령어를 전송할 때는 onCustomCommand()
, 세션에서 사용 가능한 세션 명령어를 변경할 때는 onAvailableSessionCommandsChanged()
, 컨트롤러가 세션에서 연결 해제될 때는 onDisconnected()
입니다.
MediaController.Listener
는 Builder
로 컨트롤러를 빌드할 때 설정할 수 있습니다.
Kotlin
MediaController.Builder(context, sessionToken)
.setListener(
object : MediaController.Listener {
override fun onCustomCommand(
controller: MediaController,
command: SessionCommand,
args: Bundle,
): ListenableFuture<SessionResult> {
// Handle custom command.
return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))
}
override fun onDisconnected(controller: MediaController) {
// Handle disconnection.
}
}
)
.buildAsync()
자바
new MediaController.Builder(context, sessionToken)
.setListener(
new MediaController.Listener() {
@Override
public ListenableFuture<SessionResult> onCustomCommand(
MediaController controller, SessionCommand command, Bundle args) {
// Handle custom command.
return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS));
}
@Override
public void onDisconnected(MediaController controller) {
// Handle disconnection.
}
})
.buildAsync();
다른 구성요소와 마찬가지로 MediaController
가 더 이상 필요하지 않으면 해제해야 합니다(예: Activity
또는 Fragment
의 onStop()
메서드).
Kotlin
MediaController.releaseFuture(controllerFuture)
자바
MediaController.releaseFuture(controllerFuture);
컨트롤러를 해제해도 세션에 전송된 대기 중인 모든 명령이 계속 전송되며, 이러한 명령이 처리된 후에 세션 서비스에서만 바인딩이 해제됩니다(둘 중 먼저 발생하는 경우).
MediaBrowser
만들기 및 사용
MediaBrowser
는 MediaController
에서 제공하는 기능을 기반으로 하여 미디어 앱의 MediaLibraryService
에서 제공하는 미디어 라이브러리 탐색도 지원합니다.
Kotlin
val browserFuture = MediaBrowser.Builder(context, sessionToken).buildAsync()
browserFuture.addListener({
// MediaBrowser is available here with browserFuture.get()
}, MoreExecutors.directExecutor())
자바
ListenableFuture<MediaBrowser> browserFuture =
new MediaBrowser.Builder(context, sessionToken).buildAsync();
browserFuture.addListener(() -> {
// MediaBrowser is available here with browserFuture.get()
}, MoreExecutors.directExecutor());
미디어 앱의 콘텐츠 라이브러리 탐색을 시작하려면 먼저 getLibraryRoot()
를 사용하여 루트 노드를 가져옵니다.
Kotlin
// Get the library root to start browsing the library tree.
val rootFuture = mediaBrowser.getLibraryRoot(/* params= */ null)
rootFuture.addListener({
// Root node MediaItem is available here with rootFuture.get().value
}, MoreExecutors.directExecutor())
자바
// Get the library root to start browsing the library tree.
ListenableFuture<LibraryResult<MediaItem>> rootFuture =
mediaBrowser.getLibraryRoot(/* params= */ null);
rootFuture.addListener(() -> {
// Root node MediaItem is available here with rootFuture.get().value
}, MoreExecutors.directExecutor());
그런 다음 getChildren()
를 사용하여 라이브러리의 MediaItem
하위 요소를 검색하여 미디어 라이브러리를 탐색할 수 있습니다. 예를 들어 루트 노드 MediaItem
의 하위 요소를 검색하려면 다음을 실행합니다.
Kotlin
// Get the library root to start browsing the library tree.
val childrenFuture =
mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Int.MAX_VALUE, null)
childrenFuture.addListener({
// List of children MediaItem nodes is available here with
// childrenFuture.get().value
}, MoreExecutors.directExecutor())
자바
ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> childrenFuture =
mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Integer.MAX_VALUE, null);
childrenFuture.addListener(() -> {
// List of children MediaItem nodes is available here with
// childrenFuture.get().value
}, MoreExecutors.directExecutor());
다른 미디어 앱의 재생 컨트롤 표시
다른 미디어 앱의 버튼이 있는 UI 컨트롤을 표시할 때는 해당 앱의 선언된 미디어 버튼 환경설정을 따르는 것이 중요합니다.
앱의 환경설정과 UI의 제약 조건 및 요구사항을 해결하는 가장 좋은 방법은 CommandButton.DisplayConstraints
를 사용하는 것입니다. UI에서 할 수 있는 작업의 제한사항을 정의할 수 있으며 resolve
메서드는 아이콘, 위치, 의도한 작업과 함께 표시할 버튼의 확실한 목록을 제공합니다.