Media streaming con ExoPlayer

4ec261ee5a0bd0cc.png

Screenshot: L’applicazione YouTube per Android

ExoPlayer è un lettore multimediale a livello di applicazione costruito sopra le API di basso livello di Android. ExoPlayer ha una serie di vantaggi rispetto al MediaPlayer integrato in Android. Supporta molti degli stessi formati multimediali di MediaPlayer, più i formati adattivi, come DASH e SmoothStreaming. ExoPlayer è altamente personalizzabile ed estensibile, rendendolo capace di molti casi d’uso avanzati. È un progetto open source usato dalle applicazioni di Google, tra cui YouTube e Google Play Movies & TV.

Prequisiti

  • Conoscenza moderata dello sviluppo Android e di Android Studio

Cosa farai

  • Crea un’istanza SimpleExoPlayer, che prepara e riproduce media da una varietà di fonti.
  • Integrare ExoPlayer con il ciclo di vita delle attività dell’app per supportare il backgrounding, il foregrounding e la ripresa della riproduzione in un ambiente a finestra singola o multipla.
  • Utilizzare MediaItemper creare una playlist.
  • Produrre flussi video adattivi, che adattano la qualità dei media alla larghezza di banda disponibile.
  • Registrare ascoltatori di eventi per monitorare lo stato della riproduzione e mostrare come gli ascoltatori possono essere usati per misurare la qualità della riproduzione.
  • Utilizza i componenti standard dell’UI di ExoPlayer, poi personalizzali secondo lo stile della tua app.

Di cosa avrai bisogno

  • Android Studio versione 3.5 o superiore
  • Un dispositivo Android con JellyBean (4.1) o superiore, idealmente con Nougat (7.1) o superiore in quanto supporta finestre multiple.

Prendi il codice

Per iniziare, scarica il progetto Android Studio:

Scarica lo zip

In alternativa, puoi clonare il repository GitHub:

git clone https://github.com/googlecodelabs/exoplayer-intro.git

Struttura della directory

La clonazione o la decompressione ti fornisce una cartella principale (exoplayer-intro), che contiene una cartella per ogni passo di questo codelab, insieme a tutte le risorse necessarie:

/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-00/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-01/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-02/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-03/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-04

Le cartelle exoplayer-codelab-N (dove N è 00 a 04) contengono lo stato finale desiderato di ogni passo di questo codelab. Questi sono progetti Android Studio autonomi, ognuno dei quali può essere importato.

Importa il progetto iniziale

  1. Avvia Android Studio.
  2. Scegli File > Nuovo > Importa progetto*.*
  3. Importa il progetto iniziale da exoplayer-codelab-00.

f2e5feb9ade6c7f7.png

Screenshot: Struttura del progetto durante l’importazione

Dopo la fine della compilazione, si vedono due moduli: il modulo app (di tipo applicazione) e il modulo player-lib (di tipo libreria). Il modulo app è in realtà vuoto, avendo solo un manifest. Tutto dal modulo player-lib viene unito quando l’applicazione viene costruita usando una dipendenza gradle in app/build.gradle.

app/build.gradle

dependencies { implementation project(":player-lib")}

La tua attività di lettore multimediale è tenuta nel modulo player-lib. La ragione per tenerlo in un modulo di libreria separato è che puoi condividerlo tra gli APK destinati a diverse piattaforme, come mobile e Android TV. Ti permette anche di approfittare di caratteristiche, come la consegna dinamica, che permettono alla tua funzione di riproduzione multimediale di essere installata solo quando l’utente ne ha bisogno.

  1. Deploy ed esegui l’app per controllare che tutto sia a posto. L’app dovrebbe riempire lo schermo con uno sfondo nero.

21c0dae6245fbd31.png

Screenshot: App vuota in esecuzione

Aggiungi dipendenza ExoPlayer

ExoPlayer è un progetto open source ospitato su GitHub. Ogni release è distribuita attraverso jCenter, che è uno dei repository di pacchetti predefiniti usati da Android Studio e Gradle. Ogni release è identificata in modo univoco da una stringa con il seguente formato:

com.google.android.exoplayer:exoplayer:rX.X.X

Puoi aggiungere ExoPlayer al tuo progetto semplicemente importando le sue classi e componenti UI. È piuttosto piccolo, avendo un ingombro ridotto di circa 70-300 kB a seconda delle caratteristiche incluse e dei formati supportati. La libreria ExoPlayer è divisa in moduli per permettere agli sviluppatori di importare solo le funzionalità di cui hanno bisogno. Per maggiori informazioni sulla struttura modulare di ExoPlayer, vedi Aggiungere i moduli di ExoPlayer.

  1. Aprire il file build.gradle del modulo player-lib.
  2. Aggiungere le seguenti righe alla sezione dependencies e sincronizzare il progetto.

player-lib/build.gradle

dependencies { implementation 'com.google.android.exoplayer:exoplayer-core:2.12.0'implementation 'com.google.android.exoplayer:exoplayer-dash:2.12.0'implementation 'com.google.android.exoplayer:exoplayer-ui:2.12.0'}

Aggiungi l’elemento PlayerView

  1. Apri il file delle risorse di layout activity_player.xml dal modulo player-lib.
  2. Posiziona il cursore dentro l’elemento FrameLayout.
  3. Inizia a digitare <PlayerView e lascia che Android Studio completi automaticamente l’elemento PlayerView.
  4. Usa match_parent per il width e height.
  5. Dichiara l’id come video_view.

activity_player.xml

<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent"/>

Andando avanti, ti riferisci a questo elemento UI come vista video.

  1. Nella PlayerActivity, ora devi trovare la vista video in modo da poterla impostare correttamente nel metodo onCreate dell’attività.

PlayerActivity.java

@Overrideprotected void onCreate(Bundle savedInstanceState) { playerView = findViewById(R.id.video_view);}
  1. Aggiungi il campo membro playerView alla tua classe PlayerActivity. Assicurati che il tipo di vista sia PlayerView.

Nota: Usa la funzione Quick Fix in Android Studio per aggiungere automaticamente un campo membro. Ricordati di impostare il tipo a

PlayerView

invece del default

View

b0f7f70115bb90e5.png

Screenshot: Quick fix menu for making a member field

Creare un ExoPlayer

Per riprodurre media in streaming, hai bisogno di un oggetto ExoPlayer. Il modo più semplice per crearne uno è usare la classe SimpleExoPlayer.Builder. Come suggerisce il nome, questa usa il modello del costruttore per costruire un’istanza SimpleExoPlayer.

SimpleExoPlayer è una comoda implementazione per tutti gli usi dell’interfaccia ExoPlayer.

Aggiungi un metodo privato initializePlayer per creare il tuo SimpleExoPlayer.

PlayerActivity.java

private SimpleExoPlayer player;private void initializePlayer() { player = new SimpleExoPlayer.Builder(this).build(); playerView.setPlayer(player);}

Crea un SimpleExoPlayer.Builder usando il tuo contesto, poi chiama build per creare il tuo oggetto SimpleExoPlayer. Questo viene poi assegnato a player, che dovete dichiarare come campo membro. Usate quindi playerView.setPlayer per legare il player alla sua vista corrispondente.

Crea un elemento multimediale

Il vostro player ora ha bisogno di un contenuto da riprodurre. Per questo, si crea un MediaItem. Ci sono molti tipi diversi di MediaItem, ma tu inizi a crearne uno per un file MP3 su internet.

Il modo più semplice per creare un MediaItem è usare MediaItem.fromUri, che accetta l’URI di un file multimediale. Aggiungi il MediaItem al player usando player.setMediaItem.

  1. Aggiungi il seguente codice a initializePlayer:

PlayerActivity.java

private void initializePlayer() { MediaItem mediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3)); player.setMediaItem(mediaItem);}

Nota che R.string.media_url_mp3 è definito come https://storage.googleapis.com/exoplayer-test-media-0/play.mp3 in strings.xml.

Giocare bene con il ciclo di vita dell’attività

Il nostro player può monopolizzare molte risorse tra cui memoria, CPU, connessioni di rete e codec hardware. Molte di queste risorse sono a corto di risorse, in particolare per i codec hardware dove ce ne può essere solo uno. È importante che tu rilasci queste risorse affinché le altre app le usino quando non le stai usando, come quando la tua app viene messa in background.

In altre parole, il ciclo di vita del tuo lettore dovrebbe essere legato al ciclo di vita della tua app. Per implementare questo, è necessario sovrascrivere i quattro metodi di PlayerActivity: onStart, onResume, onPause e onStop.

  1. Con PlayerActivity aperto, clicca sul menu Codice > Sovrascrivi metodi….
  2. Seleziona onStart, onResume, onPause e onStop.
  3. Inizializza il player nel callback onStart o onResume a seconda del livello API.

PlayerActivity.java

@Overridepublic void onStart() { super.onStart(); if (Util.SDK_INT >= 24) { initializePlayer(); }}@Overridepublic void onResume() { super.onResume(); hideSystemUi(); if ((Util.SDK_INT < 24 || player == null)) { initializePlayer(); }}

Il livello 24 e superiore delle API Android supporta finestre multiple. Poiché la vostra applicazione può essere visibile, ma non attiva in modalità finestra divisa, è necessario inizializzare il lettore in onStart. Android API livello 24 e inferiore richiede di aspettare il più a lungo possibile fino a quando si afferrano le risorse, quindi aspettate fino a onResume prima di inizializzare il lettore.

  1. Aggiungi il metodo hideSystemUi.

PlayerActivity.java

@SuppressLint("InlinedApi")private void hideSystemUi() { playerView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);}

hideSystemUi è un metodo helper chiamato in onResume, che vi permette di avere un’esperienza a schermo intero.

  1. Rilascia le risorse con releasePlayer (che crei a breve) in onPause e onStop.

PlayerActivity.java

@Overridepublic void onPause() { super.onPause(); if (Util.SDK_INT < 24) { releasePlayer(); }}@Overridepublic void onStop() { super.onStop(); if (Util.SDK_INT >= 24) { releasePlayer(); }}

Con API Level 24 e inferiori, non è garantito che onStop venga chiamato, quindi devi rilasciare il giocatore il prima possibile in onPause. Con il livello API 24 e superiore (che ha portato la modalità multi- e split-window), onStop è garantito che venga chiamato. Nello stato di pausa, la vostra attività è ancora visibile, quindi aspettate a rilasciare il giocatore fino a onStop.

Ora dovete creare un metodo releasePlayer che liberi le risorse del giocatore e lo distrugga.

  1. Aggiungi il seguente codice all’attività:

PlayerActivity.java

private boolean playWhenReady = true;private int currentWindow = 0;private long playbackPosition = 0;private void releasePlayer() { if (player != null) { playWhenReady = player.getPlayWhenReady(); playbackPosition = player.getCurrentPosition(); currentWindow = player.getCurrentWindowIndex(); player.release(); player = null; }}

Prima di rilasciare e distruggere il lettore, memorizza le seguenti informazioni:

  • Stato di riproduzione/pausa usando getPlayWhenReady.
  • Posizione di riproduzione corrente usando getCurrentPosition.
  • Indice della finestra corrente usando getCurrentWindowIndex. Per maggiori informazioni sulle finestre, vedi Timeline.

Questo ti permette di riprendere la riproduzione da dove l’utente ha lasciato. Tutto quello che devi fare è fornire queste informazioni di stato quando inizializzi il tuo lettore.

Preparazione finale

Tutto quello che devi fare ora è fornire le informazioni di stato che hai salvato in releasePlayer al tuo lettore durante l’inizializzazione.

  1. Aggiungi il seguente a initializePlayer:

PlayerActivity.java

private void initializePlayer() { player.setPlayWhenReady(playWhenReady); player.seekTo(currentWindow, playbackPosition); player.prepare();}

Ecco cosa succede:

  • setPlayWhenReady dice al lettore se iniziare a giocare non appena tutte le risorse per la riproduzione sono state acquisite. Poiché playWhenReady è inizialmente true, la riproduzione inizia automaticamente la prima volta che l’applicazione viene eseguita.
  • seekTo dice al lettore di cercare una certa posizione all’interno di una specifica finestra. Sia currentWindow che playbackPosition sono inizializzati a zero in modo che la riproduzione parta dall’inizio la prima volta che l’applicazione viene eseguita.
  • prepare dice al lettore di acquisire tutte le risorse necessarie per la riproduzione.

Play audio

Finalmente, hai finito! Avvia l’applicazione per riprodurre il file MP3 e vedere l’artwork incorporato.

1d049aead0483777.png

Screenshot: L’app che riproduce un singolo brano.

Testare il ciclo di vita dell’attività

Testare se l’app funziona in tutti i diversi stati del ciclo di vita dell’attività.

  1. Avvia un’altra app e metti di nuovo la tua app in primo piano. Riprende nella posizione corretta?
  2. Metti in pausa l’app e spostala sullo sfondo e poi di nuovo in primo piano. Rimane in uno stato di pausa quando è in background in stato di pausa?
  3. Ruota l’app. Come si comporta se cambi l’orientamento da verticale a orizzontale e viceversa?

Play video

Se vuoi riprodurre video, è facile come modificare l’URI dell’elemento multimediale in un file MP4.

  1. Cambia l’URI nel initializePlayer in R.string.media_url_mp4.
  2. Riavvia l’applicazione e prova il comportamento dopo essere stato messo in background anche con la riproduzione video.

PlayerActivity.java

private void initializePlayer() { MediaItem mediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3)); }

La PlayerView fa tutto. Invece dell’opera d’arte, il video viene reso a schermo intero.

4ebd0b0f98593691.png

Screenshot: L’app che riproduce il video.

Sei forte! Hai appena creato un’app per lo streaming multimediale a tutto schermo su Android, completa di gestione del ciclo di vita, stato salvato e controlli UI!

La tua app attuale riproduce un singolo file multimediale, ma se vuoi riprodurre più di un file multimediale, uno dopo l’altro? Per questo, hai bisogno di una playlist.

Le playlist possono essere create aggiungendo più MediaItem al tuo player usando addMediaItem. Questo permette una riproduzione senza soluzione di continuità e il buffering è gestito in background così l’utente non vede uno spinner di buffering quando cambia elementi multimediali.

  1. Aggiungi il seguente codice a initializePlayer:

PlayerActivity.java

private void initializePlayer() { player.setMediaItem(mediaItem); // Existing code MediaItem secondMediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3)); player.addMediaItem(secondMediaItem); }

Verifica come si comportano i controlli del player. Puoi usare 1f79fee4d082870f.pnge 39627002c03ce320.png per navigare nella sequenza di elementi multimediali.

7b5c034dafabe1bd.png

Screenshot: Controlli di riproduzione che mostrano un pulsante successivo e precedente

Questo è piuttosto comodo! Per maggiori informazioni, vedi la documentazione per gli sviluppatori su Media Items e Playlists, e questo articolo sull’API Playlist.

Lo streaming adattivo è una tecnica per lo streaming dei media che varia la qualità del flusso in base alla larghezza di banda della rete disponibile. Questo permette all’utente di sperimentare la migliore qualità dei media che la loro larghezza di banda permette.

Tipicamente, lo stesso contenuto multimediale è diviso in più tracce con qualità diverse (bit rate e risoluzioni). Il lettore sceglie una traccia in base alla larghezza di banda di rete disponibile.

Ogni traccia è divisa in pezzi di una certa durata, in genere tra 2 e 10 secondi. Questo permette al giocatore di passare rapidamente da una traccia all’altra quando cambia la larghezza di banda disponibile. Il lettore è responsabile della cucitura di questi pezzi insieme per una riproduzione senza soluzione di continuità.

Selezione adattiva delle tracce

Il cuore dello streaming adattivo è la selezione della traccia più appropriata per l’ambiente corrente. Aggiorna la tua app per riprodurre i media in streaming adattivo usando la selezione adattiva delle tracce.

  1. Aggiorna initializePlayer con il seguente codice:

PlayerActivity.java

private void initializePlayer() { if (player == null) { DefaultTrackSelector trackSelector = new DefaultTrackSelector(this); trackSelector.setParameters( trackSelector.buildUponParameters().setMaxVideoSizeSd()); player = new SimpleExoPlayer.Builder(this) .setTrackSelector(trackSelector) .build(); } // Remove or comment out. // player = new SimpleExoPlayer.Builder(this).build(); }

Prima, crea un DefaultTrackSelector, che è responsabile della scelta delle tracce nell’elemento multimediale. Poi, dite al vostro trackSelector di scegliere solo tracce di definizione standard o inferiore – un buon modo di risparmiare i dati del vostro utente a spese della qualità. Infine, passa il tuo trackSelector al tuo costruttore in modo che sia usato quando costruisci l’istanza SimpleExoPlayer.

Costruisci un MediaItem adattivo

DASH è un formato di streaming adattivo ampiamente usato. Per trasmettere contenuti DASH, è necessario creare un MediaItem come prima. Tuttavia, questa volta, dobbiamo usare un MediaItem.Builder piuttosto che fromUri.

Questo perché fromUri usa l’estensione del file per determinare il formato multimediale sottostante ma il nostro URI DASH non ha un’estensione di file quindi dobbiamo fornire un tipo MIME di APPLICATION_MPD quando costruiamo il MediaItem.

  1. Aggiornate initializePlayer come segue:

PlayerActivity.java

private void initializePlayer() { // Replace this line MediaItem mediaItem = MediaItem.fromUri(getString(R.string.media_url_mp4)); // With this MediaItem mediaItem = new MediaItem.Builder() .setUri(getString(R.string.media_url_dash)) .setMimeType(MimeTypes.APPLICATION_MPD) .build(); // Also remove the following lines MediaItem secondMediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3)); player.addMediaItem(secondMediaItem);}
  1. Riavvia l’applicazione e vedi lo streaming video adattivo con DASH in azione. È abbastanza facile con ExoPlayer!

Altri formati di streaming adattivo

HLS (MimeTypes.APPLICATION_M3U8) e SmoothStreaming (MimeTypes.APPLICATION_SS) sono altri formati di streaming adattivo comunemente usati, entrambi supportati da ExoPlayer. Per maggiori informazioni sulla costruzione di altre sorgenti multimediali adattive, vedi l’applicazione demo di ExoPlayer.

Nei passi precedenti, hai imparato come trasmettere flussi multimediali progressivi e adattivi. ExoPlayer sta facendo molto lavoro per te dietro le quinte, incluso quanto segue:

  • Allocare la memoria
  • Scaricare i file del contenitore
  • Estrarre i metadati dal contenitore
  • Decodificare i dati
  • Rendering di video, audio e testo sullo schermo e sugli altoparlanti

A volte, è utile sapere cosa sta facendo ExoPlayer in fase di esecuzione per capire e migliorare l’esperienza di riproduzione dei tuoi utenti.

Per esempio, potresti voler riflettere i cambiamenti di stato della riproduzione nell’interfaccia utente facendo quanto segue:

  • Visualizzando un indicatore di caricamento quando il lettore entra in uno stato di buffering
  • Mostrando una sovrapposizione con le opzioni “guarda il prossimo” quando la traccia è finita

ExoPlayer offre diverse interfacce ascoltatrici che forniscono callback per eventi utili. Usate un ascoltatore per registrare in quale stato si trova il giocatore.

Ascolta

  1. Dichiarate un membro privato di tipo PlaybackStateListener nella PlayerActivity.
  2. Create una costante TAG, che userete in seguito per il logging.

PlayerActivity.java

private PlaybackStateListener playbackStateListener;private static final String TAG = PlayerActivity.class.getName();
  1. Instanziare il playbackStateListener all’inizio di onCreate (non compilerà ancora, ma lo sistemerai a breve).

PlayerActivity.java

@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_player); playbackStateListener = new PlaybackStateListener();
  1. Usa Quick Fix per creare automaticamente la classe interna PlaybackStateListener.

b59ce69a22595ba7.png

Screenshot: Menu Quick Fix per creare una classe mancante

  1. Implementa l’interfaccia Player.EventListener. Questa è usata per informare su importanti eventi del giocatore, inclusi gli errori e i cambiamenti di stato della riproduzione.
  2. Overdi onPlaybackStateChanged aggiungendo il seguente codice:

PlayerActivity.java

private class PlaybackStateListener implements Player.EventListener { @Override public void onPlaybackStateChanged(int playbackState) { String stateString; switch (playbackState) { case ExoPlayer.STATE_IDLE: stateString = "ExoPlayer.STATE_IDLE -"; break; case ExoPlayer.STATE_BUFFERING: stateString = "ExoPlayer.STATE_BUFFERING -"; break; case ExoPlayer.STATE_READY: stateString = "ExoPlayer.STATE_READY -"; break; case ExoPlayer.STATE_ENDED: stateString = "ExoPlayer.STATE_ENDED -"; break; default: stateString = "UNKNOWN_STATE -"; break; } Log.d(TAG, "changed state to " + stateString); }}

onPlaybackStateChanged viene chiamato quando lo stato della riproduzione cambia. Il nuovo stato è dato dal parametro playbackState.

Il lettore può essere in uno dei seguenti quattro stati:

State

Descrizione

ExoPlayer.STATE_IDLE

Il lettore è stato istanziato, ma non è stato ancora preparato.

ExoPlayer.STATE_BUFFERING

Il lettore non è in grado di giocare dalla posizione corrente perché non sono stati bufferizzati abbastanza dati.

ExoPlayer.STATE_READY

Il lettore è in grado di giocare immediatamente dalla posizione corrente. Questo significa che il lettore inizierà a riprodurre i media automaticamente se la proprietà playWhenReady del lettore è true. Se è false, il player è in pausa.

ExoPlayer.STATE_ENDED

Il player ha finito di riprodurre il media.

Registra il tuo listener

Per far chiamare i tuoi callback, devi registrare il tuo playbackStateListener con il player. Fatelo in initializePlayer.

  1. Registra l’ascoltatore prima che il gioco sia preparato.

PlayerActivity.java

private void initializePlayer() { if (player == null) { player.addListener(playbackStateListener); player.prepare();}

Ancora una volta, dovete riordinare per evitare riferimenti penzolanti dal giocatore che potrebbero causare un memory leak.

  1. Rimuovi l’ascoltatore in releasePlayer:

PlayerActivity.java

private void releasePlayer() { if (player != null) { player.removeListener(playbackStateListener); player.release(); player = null; }}
  1. Apri logcat ed esegui l’applicazione.
  2. Usa i controlli UI per cercare, mettere in pausa e riprendere la riproduzione. Dovresti vedere lo stato di riproduzione cambiare nei log.

Vai più a fondo

ExoPlayer offre una serie di altri ascoltatori, che sono utili per capire l’esperienza di riproduzione dell’utente. Ci sono ascoltatori per audio e video, così come un AnalyticsListener, che contiene le callback di tutti gli ascoltatori. Alcuni dei metodi più importanti sono i seguenti:

  • onRenderedFirstFrame viene chiamato quando il primo fotogramma di un video viene reso. Con questo, si può calcolare quanto tempo l’utente ha dovuto aspettare per vedere un contenuto significativo sullo schermo.
  • onDroppedVideoFrames viene chiamato quando i fotogrammi del video sono stati abbandonati. I fotogrammi caduti indicano che la riproduzione è disturbata e l’esperienza dell’utente sarà probabilmente scarsa.
  • onAudioUnderrun viene chiamato quando c’è stato un underrun audio. Gli underrun causano glitch udibili nel suono e sono più evidenti dei fotogrammi video caduti.

AnalyticsListener può essere aggiunto al player con addAnalyticsListener. Ci sono metodi corrispondenti anche per gli ascoltatori audio e video.

Pensa a quali eventi sono importanti per la tua app e per i tuoi utenti. Per maggiori informazioni, vedi Ascoltare gli eventi del lettore. Questo è tutto per gli ascoltatori di eventi!

Finora hai usato il PlayerControlView di ExoPlayer per mostrare un controller di riproduzione all’utente.

bcfe17eebcad9e13.png

Screenshot: Controller di riproduzione predefinito

E se vuoi cambiare la funzionalità o l’aspetto di questi controlli? Fortunatamente, questi controlli sono altamente personalizzabili.

La prima semplice personalizzazione è quella di non usare affatto il controller. Questo può essere fatto facilmente usando l’attributo use_controller sull’elemento PlayerView dentro activity_player.xml.

  1. Imposta use_controller a false e il controllo non appare più:

activity_player.xml

<com.google.android.exoplayer2.ui.PlayerView app:use_controller="false"/>
  1. Aggiungi il seguente spazio dei nomi al tuo FrameLayout:

activity_player.xml

<FrameLayout xmlns:app="http://schemas.android.com/apk/res-auto">

Prova ora.

Personalizza il comportamento

PlayerControlView ha diversi attributi che influenzano il suo comportamento. Usa show_timeout, fastforward_increment e rewind_increment per personalizzare il comportamento del controller.

  1. Rimuovi app:use_controller="false".
  2. Cambia la vista del giocatore per usare show_timeout, fastforward_increment e rewind_increment:

activity_player.xml

<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent" app:show_timeout="10000" app:fastforward_increment="30000" app:rewind_increment="30000"/>
  • Il valore show_timeout dice al PlayerView il ritardo in millisecondi prima che il controllo sia nascosto dopo l’ultima interazione dell’utente.
  • I valori fastforward_increment e rewind_increment dicono al lettore il tempo in millisecondi per saltare avanti o indietro quando l’utente tocca i pulsanti fast-forward o rewind.

Gli attributi del PlayerControlView possono anche essere impostati programmaticamente.

Personalizza l’aspetto

Bene, questo è un buon inizio. Ma cosa succede se vuoi che il PlayerControlViewlook sia diverso o cambiare quali pulsanti sono visualizzati? L’implementazione di PlayerControlView non presuppone che ci siano pulsanti, quindi è facile rimuoverli e aggiungerne di nuovi.

Guarda come puoi personalizzare il PlayerControlView.

  1. Crea un nuovo file di layout custom_player_control_view.xml nella cartella player-lib/res/layout/.
  2. Dal menu contestuale della cartella del layout, scegli Nuovo – File risorse di layout e nominalo custom_player_control_view.xml.

ae1e3795726d4e4e.png

Screenshot: Il file di layout per la vista di controllo del giocatore è stato creato.

  1. Copia il file di layout originale da qui a custom_player_control_view.xml.
  2. Rimuovi gli elementi ImageButton con gli id @id/exo_prev e @id/exo_next.

Per usare il tuo layout personalizzato, devi impostare l’attributo app:controller_layout_id dell’elemento PlayerView nel file activity_player.xml.

  1. Usa l’ID del layout del tuo file personalizzato come nel seguente frammento di codice:

activity_player.xml

<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent" app:controller_layout_id="@layout/custom_player_control_view"/>
  1. Riavvia l’applicazione. La vista di controllo del giocatore non ha più i pulsanti precedente e successivo.

89e6535a22c8e321.png

Screenshot: Vista di controllo del giocatore personalizzata senza pulsanti precedente e successivo

Puoi applicare qualsiasi modifica tu voglia nel file di layout. Per impostazione predefinita, vengono scelti i colori del tema di Android. Puoi sovrascriverli per adattarli al design della tua applicazione.

  1. Aggiungi un attributo android:tint ad ogni elemento ImageButton:

custom_player_control_view.xml

<ImageButton android:id="@id/exo_rew" android:tint="#FF00A6FF" style="@style/ExoMediaButton.Rewind"/>
  1. Cambia tutti gli attributi android:textColor che trovi nel tuo file personalizzato con lo stesso colore: #FF00A6FF.

custom_player_control_view.xml

<TextView android:id="@id/exo_position" android:textColor="#FF00A6FF"/><TextView android:id="@id/exo_duration" android:textColor="#FF00A6FF"/>
  1. Lancia l’applicazione. Ora hai dei bellissimi componenti UI colorati!

e9835d65d6dd0634.png

Screenshot: Pulsanti colorati e visualizzazione del testo

Sovrascrivi lo stile predefinito

Hai appena creato un file di layout personalizzato e lo hai referenziato usando controller_layout_id in activity_player.xml.

Un altro approccio è quello di sovrascrivere il file di layout predefinito che PlayerControlView usa. Il codice sorgente di PlayerControlView ci dice che usa R.layout.exo_player_control_view per il layout. Se creiamo il nostro file di layout con lo stesso nome, il PlayerControlView usa il tuo file al suo posto.

  1. Rimuovi l’attributo controller_layout_id che hai appena aggiunto.
  2. Elimina il file custom_player_control_view.xml.

Il PlayerView in activity_player.xml dovrebbe ora essere così:

activity_player.xml

<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent"/>
  1. Crea un file chiamato exo_player_control_view.xml nella cartella res/layout del tuo modulo di libreria player-lib.
  2. Inserisci il seguente codice in exo_player_control_view.xml per aggiungere un pulsante play, un pulsante pausa e un ImageView con un logo:

exo_player**_control_view.xml**

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layoutDirection="ltr" android:background="#CC000000" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:paddingTop="4dp" android:orientation="horizontal"> <ImageButton android:id="@id/exo_play" style="@style/ExoMediaButton.Play"/> <ImageButton android:id="@id/exo_pause" style="@style/ExoMediaButton.Pause"/> </LinearLayout> <ImageView android:contentDescription="@string/logo" android:src="@drawable/google_logo" android:layout_width="match_parent" android:layout_height="wrap_content"/></LinearLayout>

Questo dimostra come puoi aggiungere i tuoi elementi qui e mescolarli con elementi di controllo standard. ExoPlayerView ora usa il tuo controllo personalizzato e tutta la logica per nascondere e mostrare quando si interagisce con il controllo è conservata.

Congratulazioni! Hai imparato molto sull’integrazione di ExoPlayer con la tua app.

Impara di più

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.