An app playing media requires user interface components for displaying media and controlling playback. The Media3 library includes a UI module that contains a number of UI components. To depend on the UI module add the following dependency:
Kotlin
implementation("androidx.media3:media3-ui:1.5.1")
Groovy
implementation "androidx.media3:media3-ui:1.5.1"
The most important component is PlayerView
, a view for media playbacks.
PlayerView
displays video, images, subtitles, and album art during playback,
as well as playback controls.
PlayerView
has a setPlayer
method for attaching and detaching (by
passing null
) player instances.
PlayerView
PlayerView
can be used for both video, image and audio playbacks. It renders
video and subtitles in the case of video playback, bitmaps for image playback
and can display artwork included as metadata in audio files. You can include it
in your layout files like any other UI component. For example, a PlayerView
can be included with the following XML:
<androidx.media3.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:show_buffering="when_playing"
app:show_shuffle_button="true"/>
The snippet above illustrates that PlayerView
provides several
attributes. These attributes can be used to customize the view's behavior, as
well as its look and feel. Most of these attributes have corresponding setter
methods, which can be used to customize the view at runtime. The
PlayerView
Javadoc lists these attributes and setter methods in
more detail.
Once the view is declared in the layout file, it can be looked up in the
onCreate
method of the activity:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... playerView = findViewById(R.id.player_view) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... playerView = findViewById(R.id.player_view); }
When a player has been initialized, it can be attached to the view by calling
setPlayer
:
Kotlin
// Instantiate the player. val player = ExoPlayer.Builder(context).build() // Attach player to the view. playerView.player = player // Set the media item to be played. player.setMediaItem(mediaItem) // Prepare the player. player.prepare()
Java
// Instantiate the player. player = new ExoPlayer.Builder(context).build(); // Attach player to the view. playerView.setPlayer(player); // Set the media item to be played. player.setMediaItem(mediaItem); // Prepare the player. player.prepare();
Choose a surface type
The surface_type
attribute of PlayerView
lets you set the type of surface
used for video playback. Besides the values spherical_gl_surface_view
(which
is a special value for spherical video playback) and
video_decoder_gl_surface_view
(which is for video rendering using extension
renderers), the allowed values are surface_view
, texture_view
and none
. If
the view is for audio playback only, none
should be used to avoid having to
create a surface because doing so can be expensive.
If the view is for regular video playback then surface_view
or texture_view
should be used. SurfaceView
has a number of benefits over TextureView
for
video playback:
- Significantly lower power consumption on many devices.
- More accurate frame timing, resulting in smoother video playback.
- Support for higher quality HDR video output on capable devices.
- Support for secure output when playing DRM-protected content.
- The ability to render video content at the full resolution of the display on Android TV devices that upscale the UI layer.
SurfaceView
should therefore be preferred over TextureView
where possible.
TextureView
should be used only if SurfaceView
does not meet your needs. One
example is where smooth animations or scrolling of the video surface is required
prior to Android 7.0 (API level 24), as described in the following notes. For
this case, it's preferable to use TextureView
only when SDK_INT
is less
than 24 (Android 7.0) and SurfaceView
otherwise.
D-pad navigation on Android TV
The remote control of Android TV has a D-pad control that sends commands that
arrive as key event at dispatchKeyEvent(KeyEvent)
of your Activity
. These
need to be delegated to the player view:
Kotlin
override fun dispatchKeyEvent(event: KeyEvent?): Boolean{ return playerView.dispatchKeyEvent(event!!) || super.dispatchKeyEvent(event) }
Java
@Override public boolean dispatchKeyEvent(KeyEvent event) { return playerView.dispatchKeyEvent(event) || super.dispatchKeyEvent(event); }
Requesting focus for the player view is important for navigating playback
controls and skipping ads. Consider requesting the focus in onCreate
of the
Activity
:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... playerView.requestFocus() // ... }
Java
@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... playerView.requestFocus(); // ... }
If you are using Compose on Android TV, you need to make the AndroidView
focusable and delegate the event by passing the modifier parameter into the
AndroidView
accordingly:
AndroidView(
modifier = modifier
.focusable()
.onKeyEvent { playerView.dispatchKeyEvent(it.nativeKeyEvent) },
factory = { playerView }
)
Override drawables
PlayerView
uses PlayerControlView
to display the playback
controls and progress bar. The drawables used by PlayerControlView
can
be overridden by drawables with the same names defined in your application. See
the PlayerControlView
Javadoc for a list of control drawables that
can be overridden.
Further customization
Where customization beyond that described above is required, we expect that app developers will implement their own UI components rather than use those provided by Media3's UI module.