Creare un'app di media player di base utilizzando Media3 ExoPlayer

Jetpack Media3 definisce un'interfaccia Player che delinea le funzionalità di base per la riproduzione di file video e audio. ExoPlayer è l'implementazione predefinita di questa interfaccia in Media3. Consigliamo di utilizzare ExoPlayer, poiché fornisce un insieme completo di funzionalità che copre la maggior parte dei casi d'uso di riproduzione ed è personalizzabile per gestire eventuali casi d'uso aggiuntivi. ExoPlayer rimuove anche la frammentazione del dispositivo e del sistema operativo in modo che il tuo codice funzioni in modo coerente sull'intero ecosistema Android. ExoPlayer include:

In questa pagina vengono illustrati alcuni dei passaggi chiave per la creazione di un'app di riproduzione. Per ulteriori dettagli, puoi consultare le nostre guide complete su Media3 ExoPlayer.

Per iniziare

Per iniziare, aggiungi una dipendenza ai moduli ExoPlayer, alla UI e ai moduli comuni di Jetpack Media3:

implementation "androidx.media3:media3-exoplayer:1.3.1"
implementation "androidx.media3:media3-ui:1.3.1"
implementation "androidx.media3:media3-common:1.3.1"

A seconda del caso d'uso, potrebbero essere necessari anche moduli aggiuntivi di Media3, ad esempio exoplayer-dash, per riprodurre stream nel formato DASH.

Assicurati di sostituire 1.3.1 con la tua versione preferita della libreria. Per conoscere la versione più recente, consulta le note di rilascio.

Creazione di un media player

Con Media3 puoi utilizzare l'implementazione inclusa dell'interfaccia Player ExoPlayer oppure creare una tua implementazione personalizzata.

Creazione di un ExoPlayer

Il modo più semplice per creare un'istanza ExoPlayer è il seguente:

Kotlin

val player = ExoPlayer.Builder(context).build()

Java

ExoPlayer player = new ExoPlayer.Builder(context).build();

Puoi creare il media player nel metodo del ciclo di vita onCreate() di Activity, Fragment o Service in cui si trova.

La Builder include una serie di opzioni di personalizzazione che potrebbero interessarti, ad esempio:

Media3 fornisce un componente UI PlayerView che puoi includere nel file di layout della tua app. Questo componente incapsula un PlayerControlView per i controlli di riproduzione, un SubtitleView per la visualizzazione dei sottotitoli e un Surface per il rendering del video.

Preparazione del player

Aggiungi elementi multimediali a una playlist per riprodurli con metodi quali setMediaItem() e addMediaItem(). Quindi, chiama prepare() per iniziare a caricare i contenuti multimediali e acquisire le risorse necessarie.

Non eseguire questi passaggi prima che l'app sia in primo piano. Se il tuo player è in un Activity o Fragment, significa che deve prepararlo nel metodo del ciclo di vita onStart() a partire dal livello API 24 e nel metodo di ciclo di vita onResume() a partire dal livello API 23. Per un giocatore in un Service, puoi prepararlo in onCreate().

Controllare il player

Una volta preparato il player, puoi controllare la riproduzione richiamando metodi sul player, ad esempio:

I componenti dell'interfaccia utente come PlayerView o PlayerControlView verranno aggiornati di conseguenza se associati a un player.

Rilascia il player

La riproduzione può richiedere risorse limitate, come i decoder video, quindi è importante chiamare release() sul player per liberare risorse quando il player non è più necessario.

Se il player si trova in un Activity o Fragment, rilascialo nel metodo del ciclo di vita onStop() a partire dal livello API 24 o con il metodo onPause() con il livello API 23 e versioni precedenti. Per un giocatore che si trova in un Service, puoi rilasciarlo in onDestroy().

Gestione della riproduzione con una sessione multimediale

Su Android, le sessioni multimediali offrono un modo standardizzato per interagire con un lettore multimediale oltre i confini dei processi. Il collegamento di una sessione multimediale al player ti consente di pubblicizzare la riproduzione di contenuti multimediali esternamente e di ricevere comandi di riproduzione da fonti esterne, ad esempio per l'integrazione con i controlli multimediali di sistema su dispositivi mobili e schermi di grandi dimensioni.

Per utilizzare le sessioni multimediali, aggiungi una dipendenza nel modulo Sessione Media3:

implementation "androidx.media3:media3-session:1.3.1"

Creare una sessione multimediale

Puoi creare un MediaSession dopo aver inizializzato un player nel seguente modo:

Kotlin

val player = ExoPlayer.Builder(context).build()
val mediaSession = MediaSession.Builder(context, player).build()

Java

ExoPlayer player = new ExoPlayer.Builder(context).build();
MediaSession mediaSession = new MediaSession.Builder(context, player).build();

Media3 sincronizza automaticamente lo stato di Player con lo stato di MediaSession. Questo vale con qualsiasi implementazione di Player, tra cui ExoPlayer, CastPlayer o un'implementazione personalizzata.

Concedi il controllo ad altri clienti

Le app client possono implementare un controller multimediale per controllare la riproduzione della sessione multimediale. Per ricevere queste richieste, imposta un oggetto callback durante la creazione di MediaSession.

Quando un controller sta per connettersi alla sessione multimediale, viene chiamato il metodo onConnect(). Puoi utilizzare il ControllerInfo fornito per decidere se accettare o rifiutare la richiesta. Guarda un esempio nell'app demo Media3 Session.

Una volta collegato, un controller può inviare comandi di riproduzione alla sessione. La sessione delega quindi questi comandi al player. I comandi di riproduzione e playlist definiti nell'interfaccia Player vengono gestiti automaticamente dalla sessione.

Altri metodi di callback ti consentono di gestire, ad esempio, le richieste di comandi di riproduzione personalizzati e la modifica della playlist. In modo analogo, questi callback includono un oggetto ControllerInfo, che ti consente di determinare il controllo dell'accesso in base alle singole richieste.

Riproduzione di contenuti multimediali in background

Per continuare a riprodurre contenuti multimediali quando la tua app non è in primo piano, ad esempio per riprodurre musica, audiolibri o podcast anche quando l'utente non ha l'app aperta, Player e MediaSession devono essere incorporati in un servizio in primo piano. A questo scopo, Media3 fornisce l'interfaccia MediaSessionService.

Implementazione di un MediaSessionService

Crea un corso che estende MediaSessionService e crea un'istanza di MediaSession nel metodo del ciclo di vita onCreate().

Kotlin

class PlaybackService : MediaSessionService() {
    private var mediaSession: MediaSession? = null

    // Create your Player and MediaSession in the onCreate lifecycle event
    override fun onCreate() {
        super.onCreate()
        val player = ExoPlayer.Builder(this).build()
        mediaSession = MediaSession.Builder(this, player).build()
    }

    // Remember to release the player and media session in onDestroy
    override fun onDestroy() {
        mediaSession?.run {
            player.release()
            release()
            mediaSession = null
        }
        super.onDestroy()
    }
}

Java

public class PlaybackService extends MediaSessionService {
    private MediaSession mediaSession = null;

    @Override
    public void onCreate() {
        super.onCreate();
        ExoPlayer player = new ExoPlayer.Builder(this).build();
        mediaSession = new MediaSession.Builder(this, player).build();
    }

    @Override
    public void onDestroy() {
        mediaSession.getPlayer().release();
        mediaSession.release();
        mediaSession = null;
        super.onDestroy();
    }
}

Nel file manifest, la classe Service con un filtro per intent MediaSessionService e richiedere l'autorizzazione FOREGROUND_SERVICE per eseguire un servizio in primo piano:

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaSessionService"/>
    </intent-filter>
</service>

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Infine, nel corso che hai creato, sostituisci il metodo onGetSession() per controllare l'accesso del client alla tua sessione multimediale. Restituisci un MediaSession per accettare la richiesta di connessione oppure restituisce null per rifiutare la richiesta.

Kotlin

// This example always accepts the connection request
override fun onGetSession(
    controllerInfo: MediaSession.ControllerInfo
): MediaSession? = mediaSession

Java

@Override
public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) {
  // This example always accepts the connection request
  return mediaSession;
}

Connessione all'interfaccia utente in corso...

Ora che la tua sessione multimediale si trova in un Service separato da Activity o Fragment in cui si trova l'UI del tuo player, puoi utilizzare MediaController per collegarli. Nel metodo onStart() di Activity o Fragment con la tua UI, crea un SessionToken per MediaSession, quindi usa SessionToken per creare un MediaController. La creazione di un MediaController avviene in modo asincrono.

Kotlin

override fun onStart() {
  val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java))
  val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync()
  controllerFuture.addListener(
    {
        // Call controllerFuture.get() to retrieve the MediaController.
        // MediaController implements the Player interface, so it can be
        // attached to the PlayerView UI component.
        playerView.setPlayer(controllerFuture.get())
      },
    MoreExecutors.directExecutor()
  )
}

Java

@Override
public void onStart() {
  SessionToken sessionToken =
    new SessionToken(this, new ComponentName(this, PlaybackService.class));
  ListenableFuture<MediaController> controllerFuture =
    new MediaController.Builder(this, sessionToken).buildAsync();
  controllerFuture.addListener(() -> {
    // Call controllerFuture.get() to retrieve the MediaController.
    // MediaController implements the Player interface, so it can be
    // attached to the PlayerView UI component.
    playerView.setPlayer(controllerFuture.get());
  }, MoreExecutors.directExecutor())
}

MediaController implementa l'interfaccia Player, quindi puoi usare gli stessi metodi, ad esempio play() e pause(), per controllare la riproduzione. Come per gli altri componenti, ricordati di rilasciare MediaController quando non è più necessario, ad esempio il metodo del ciclo di vita onStop() di un Activity, chiamando MediaController.releaseFuture().

Pubblicazione di una notifica

I servizi in primo piano sono tenuti a pubblicare una notifica quando sono attivi. Un MediaSessionService creerà automaticamente una notifica MediaStyle per te sotto forma di MediaNotification. Per fornire una notifica personalizzata, crea una MediaNotification.Provider con DefaultMediaNotificationProvider.Builder o un'implementazione personalizzata dell'interfaccia del provider. Aggiungi il tuo provider a MediaSession con setMediaNotificationProvider.

Pubblicizzare la raccolta di contenuti

Un MediaLibraryService si basa su MediaSessionService consentendo alle app client di sfogliare i contenuti multimediali forniti dalla tua app. Le app client implementano MediaBrowser per interagire con MediaLibraryService.

L'implementazione di un MediaLibraryService è simile all'implementazione di un MediaSessionService, tranne per il fatto che in onGetSession() devi restituire un MediaLibrarySession anziché un MediaSession. Rispetto a MediaSession.Callback, MediaLibrarySession.Callback include metodi aggiuntivi che consentono a un client del browser di esplorare i contenuti offerti dal tuo servizio di libreria.

Analogamente a MediaSessionService, dichiara il MediaLibraryService nel file manifest e richiedi l'autorizzazione FOREGROUND_SERVICE per eseguire un servizio in primo piano:

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaLibraryService"/>
        <action android:name="android.media.browse.MediaBrowserService"/>
    </intent-filter>
</service>

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

L'esempio precedente include un filtro per intent sia per MediaLibraryService sia, per la compatibilità con le versioni precedenti, per la versione MediaBrowserService precedente. Il filtro per intent aggiuntivo consente alle app client che utilizzano l'API MediaBrowserCompat di riconoscere Service.

Un MediaLibrarySession ti consente di pubblicare la tua libreria di contenuti in una struttura ad albero con un singolo MediaItem principale. Ogni MediaItem nell'albero può avere un numero illimitato di nodi MediaItem secondari. Puoi pubblicare una radice diversa o un albero diverso, in base alla richiesta dell'app client. Ad esempio, la struttura ad albero restituita a un client che cerca un elenco di elementi multimediali consigliati potrebbe contenere solo il nodo principale MediaItem e un singolo livello di nodi MediaItem secondari, mentre la struttura ad albero che torni a un'altra app client potrebbe rappresentare una libreria di contenuti più completa.

Creazione di un MediaLibrarySession in corso...

Una MediaLibrarySession estende l'API MediaSession per aggiungere API di navigazione dei contenuti. Rispetto al callback MediaSession, il callback MediaLibrarySession aggiunge metodi come:

  • onGetLibraryRoot() quando un client richiede la radice MediaItem di una struttura di contenuti
  • onGetChildren() per quando un client richiede gli elementi secondari di una MediaItem nell'albero dei contenuti
  • onGetSearchResult() quando un client richiede i risultati di ricerca dalla struttura ad albero dei contenuti per una determinata query

I metodi di callback pertinenti includeranno un oggetto LibraryParams con indicatori aggiuntivi sul tipo di albero dei contenuti a cui è interessata un'app client.