Streaming media cu ExoPlayer

4ec261ee5a0bd0cc.png

Captură de ecran: Aplicația YouTube pentru Android

ExoPlayer este un player media la nivel de aplicație construit pe API-urile media de nivel scăzut din Android. ExoPlayer are o serie de avantaje față de MediaPlayer încorporat în Android. Acesta acceptă multe dintre aceleași formate media ca MediaPlayer, plus formate adaptive, cum ar fi DASH și SmoothStreaming. ExoPlayer este foarte personalizabil și extensibil, ceea ce îl face capabil de multe cazuri de utilizare avansată. Este un proiect open source utilizat de aplicațiile Google, inclusiv YouTube și Google Play Movies & TV.

Precondiții

  • Cunoștințe moderate de dezvoltare Android și Android Studio

Ce veți face

  • Crearea unei instanțe SimpleExoPlayer, care pregătește și redă conținut media dintr-o varietate de surse.
  • Integrați ExoPlayer cu ciclul de viață al activității aplicației pentru a suporta trecerea în fundal, în prim-plan și reluarea redării într-un mediu cu o singură fereastră sau cu mai multe ferestre.
  • Utilizați MediaItems pentru a crea o listă de redare.
  • Reproduceți fluxuri video adaptive, care adaptează calitatea media la lățimea de bandă disponibilă.
  • Înregistrați ascultători de evenimente pentru a monitoriza starea de redare și arătați cum pot fi utilizați ascultătorii pentru a măsura calitatea redării.
  • Utilizați componentele standard ExoPlayer UI, apoi personalizați-le în funcție de stilul aplicației dumneavoastră.

De ce aveți nevoie

  • Android Studio versiunea 3.5 sau mai recentă
  • Un dispozitiv Android cu JellyBean (4.1) sau mai recentă, ideal cu Nougat (7.1) sau mai recentă, deoarece acceptă ferestre multiple.

Obțineți codul

Pentru a începe, descărcați proiectul Android Studio:

Download zip

Alternativ, puteți clona depozitul GitHub:

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

Structura directoarelor

Clonarea sau dezarhivarea vă oferă un dosar rădăcină (exoplayer-intro), care conține un dosar pentru fiecare etapă a acestui codelab, împreună cu toate resursele de care aveți nevoie:

/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

Directoarele exoplayer-codelab-N (unde N sunt de la 00 la 04) conțin starea finală dorită a fiecărei etape a acestui codelab. Acestea sunt proiecte Android Studio de sine stătătoare, care pot fi importate fiecare.

Importă proiectul inițial

  1. Pornește Android Studio.
  2. Alege File > New > Import Project*.*
  3. Importă proiectul inițial din exoplayer-codelab-00.

f2e5feb9ade6c7f7.png

Captură de ecran: Structura proiectului la import

După ce se termină compilarea, veți vedea două module: modulul app (de tip aplicație) și modulul player-lib (de tip bibliotecă). Modulul app este de fapt gol, având doar un manifest. Tot ceea ce provine din modulul player-lib este fuzionat atunci când aplicația este construită folosind o dependență gradle în app/build.gradle.

app/build.gradle

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

Activitatea playerului dvs. media este păstrată în modulul player-lib. Motivul pentru care o păstrați într-un modul de bibliotecă separat este pentru a o putea partaja între APK-uri care vizează diferite platforme, cum ar fi mobilul și Android TV. De asemenea, vă permite să profitați de caracteristici, cum ar fi Dynamic Delivery (Livrare dinamică), care permit ca funcția dvs. de redare media să fie instalată numai atunci când utilizatorul are nevoie de ea.

  1. Deplasați și rulați aplicația pentru a verifica dacă totul este în regulă. Aplicația ar trebui să umple ecranul cu un fundal negru.

21c0dae6245fbd31.png

Captură de ecran: Blank app running

Add ExoPlayer dependency

ExoPlayer este un proiect open source găzduit pe GitHub. Fiecare versiune este distribuită prin jCenter, care este unul dintre depozitele de pachete implicite utilizate de Android Studio și Gradle. Fiecare versiune este identificată în mod unic printr-un șir de caractere cu următorul format:

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

Puteți adăuga ExoPlayer în proiectul dumneavoastră prin simpla importăre a claselor și a componentelor UI ale acestuia. Este destul de mic, având o amprentă micșorată de aproximativ 70-300 kB în funcție de caracteristicile incluse și de formatele acceptate. Biblioteca ExoPlayer este împărțită în module pentru a permite dezvoltatorilor să importe doar funcționalitatea de care au nevoie. Pentru mai multe informații despre structura modulară a ExoPlayer, consultați Adăugarea modulelor ExoPlayer.

  1. Deschideți fișierul build.gradle al modulului player-lib.
  2. Adaugați următoarele linii la secțiunea dependencies și sincronizați proiectul.

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

Adaugați elementul PlayerView

  1. Deschideți fișierul de resurse layout activity_player.xml din modulul player-lib.
  2. Puneți cursorul în interiorul elementului FrameLayout.
  3. Începeți să tastați <PlayerView și lăsați Android Studio să autocompleteze elementul PlayerView.
  4. Utilizați match_parent pentru width și height.
  5. Declarați id-ul ca fiind 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"/>

În continuare, vă referiți la acest element UI ca fiind vizualizarea video.

  1. În PlayerActivity, acum trebuie să găsiți vizualizarea video, astfel încât să o puteți configura corect în metoda onCreate a activității.

PlayerActivity.java

@Overrideprotected void onCreate(Bundle savedInstanceState) { playerView = findViewById(R.id.video_view);}
  1. Adaugați câmpul membru playerView la clasa PlayerActivity. Asigurați-vă că tipul de vizualizare este PlayerView.

Nota: Utilizați funcția Quick Fix din Android Studio pentru a adăuga automat un câmp membru. Nu uitați să setați tipul la

PlayerView

în loc de tipul implicit

View

b0f7f70115bb90e5.png

Captură de ecran: Meniu de remediere rapidă pentru crearea unui câmp membru

Crearea unui ExoPlayer

Pentru a reda conținut media în flux, aveți nevoie de un obiect ExoPlayer. Cel mai simplu mod de a crea unul este să folosiți clasa SimpleExoPlayer.Builder. După cum sugerează și numele, aceasta folosește modelul constructor pentru a construi o instanță SimpleExoPlayer.

SimpleExoPlayer este o implementare convenabilă, cu destinație generală, a interfeței ExoPlayer.

Adaugați o metodă privată initializePlayer pentru a vă crea SimpleExoPlayer.

PlayerActivity.java

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

Creați un SimpleExoPlayer.Builder folosind contextul dumneavoastră, apoi apelați build pentru a vă crea obiectul SimpleExoPlayer. Acesta este apoi atribuit la player, pe care trebuie să îl declarați ca un câmp membru. Folosiți apoi playerView.setPlayer pentru a lega player de vizualizarea sa corespunzătoare.

Crearea unui element media

Acest player al dvs. are acum nevoie de un conținut pentru a fi redat. Pentru aceasta, creați un MediaItem. Există multe tipuri diferite de MediaItem, dar începeți prin a crea unul pentru un fișier MP3 de pe internet.

Cel mai simplu mod de a crea un MediaItem este de a folosi MediaItem.fromUri, care acceptă URI-ul unui fișier media. Adăugați MediaItem la player folosind player.setMediaItem.

  1. Adaugați următorul cod la initializePlayer:

PlayerActivity.java

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

Rețineți că R.string.media_url_mp3 este definit ca https://storage.googleapis.com/exoplayer-test-media-0/play.mp3 în strings.xml.

Jucând frumos cu ciclul de viață al Activității

Noi player putem acapara o mulțime de resurse, inclusiv memorie, CPU, conexiuni de rețea și codecuri hardware. Multe dintre aceste resurse sunt în criză, în special pentru codecurile hardware, unde poate exista doar unul singur. Este important să eliberați aceste resurse pentru ca alte aplicații să le folosească atunci când nu le folosiți, cum ar fi atunci când aplicația dvs. este pusă în fundal.

După cumva, ciclul de viață al playerului dvs. ar trebui să fie legat de ciclul de viață al aplicației dvs. Pentru a implementa acest lucru, trebuie să suprascrieți cele patru metode din PlayerActivity: onStart, onResume, onPause și onStop.

  1. Cu PlayerActivity deschis, faceți clic pe meniul Code > Override methods….
  2. Selectați onStart, onResume, onPause și onStop.
  3. Inițializați playerul în callback-ul onStart sau onResume, în funcție de nivelul 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(); }}

Android API level 24 și mai mare suportă ferestre multiple. Deoarece aplicația dvs. poate fi vizibilă, dar nu activă în modul cu ferestre divizate, trebuie să inițializați playerul în onStart. Android API de nivel 24 și inferior vă cere să așteptați cât mai mult timp posibil până la preluarea resurselor, așa că așteptați până la onResume înainte de a inițializa playerul.

  1. Adaugați metoda 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 este o metodă de ajutor apelată în onResume, care vă permite să aveți o experiență de ecran complet.

  1. Liberați resursele cu releasePlayer (pe care o creați în scurt timp) în onPause și 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(); }}

Cu API Level 24 și mai mici, nu există nicio garanție că onStop va fi apelată, astfel încât trebuie să eliberați jucătorul cât mai devreme posibil în onPause. Cu API Level 24 și mai sus (care a adus modul multi- și split-window), onStop este garantat să fie apelat. În starea de pauză, activitatea dvs. este încă vizibilă, așa că așteptați să eliberați jucătorul până la onStop.

Acum trebuie să creați o metodă releasePlayer, care eliberează resursele jucătorului și îl distruge.

  1. Adaugați următorul cod la activitate:

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

Înainte de a elibera și distruge playerul, stocați următoarele informații:

  • Starea de redare/pausare folosind getPlayWhenReady.
  • .

  • Positia curentă de redare folosind getCurrentPosition.
  • .

  • Indicatorul curent al ferestrei folosind getCurrentWindowIndex. Pentru mai multe informații despre ferestre, consultați Timeline.

Aceasta vă permite să reluați redarea din punctul în care a fost întreruptă de utilizator. Tot ce trebuie să faceți este să furnizați aceste informații de stare atunci când vă inițializați playerul.

Pregătire finală

Tot ce trebuie să faceți acum este să furnizați informațiile de stare pe care le-ați salvat în releasePlayer playerului dumneavoastră în timpul inițializării.

  1. Adaugați următoarele la initializePlayer:

PlayerActivity.java

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

Iată ce se întâmplă:

  • setPlayWhenReady spune jucătorului dacă trebuie să înceapă redarea imediat ce toate resursele pentru redare au fost achiziționate. Deoarece playWhenReady este inițial true, redarea începe automat la prima rulare a aplicației.
  • seekTo îi spune playerului să caute o anumită poziție în cadrul unei anumite ferestre. Atât currentWindow, cât și playbackPosition sunt inițializate la zero, astfel încât redarea începe chiar de la început, la prima rulare a aplicației.
  • prepare îi spune playerului să achiziționeze toate resursele necesare pentru redare.

Reducere audio

În sfârșit, ați terminat! Porniți aplicația pentru a reda fișierul MP3 și pentru a vedea ilustrația încorporată.

1d049aead0483777.png

Captură de ecran: Aplicația care redă o singură piesă.

Testați ciclul de viață al activității

Testați dacă aplicația funcționează în toate stările diferite ale ciclului de viață al activității.

  1. Porniți o altă aplicație și puneți din nou aplicația dvs. în prim-plan. Se reia în poziția corectă?
  2. Păsați aplicația și treceți-o în fundal și apoi din nou în prim-plan. Rămâne în stare de pauză atunci când se află în fundal în stare de pauză?
  3. Rotați aplicația. Cum se comportă dacă schimbați orientarea din portret în peisaj și invers?

Play video

Dacă doriți să redați video, este la fel de simplu ca și cum ați modifica URI-ul elementului media într-un fișier MP4.

  1. Modificați URI-ul din initializePlayer în R.string.media_url_mp4.
  2. Reporniți din nou aplicația și testați comportamentul după ce este în fundal și cu redare video.

PlayerActivity.java

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

Cel PlayerView face totul. În loc de opera de artă, videoclipul este redat pe tot ecranul.

4ebd0b0f98593691.png

Captură de ecran: Aplicația care redă video.

You rock! Tocmai ați creat o aplicație pentru streaming media pe ecran complet pe Android, cu management al ciclului de viață, stare salvată și controale UI!

Aplicația dvs. actuală redă un singur fișier media, dar ce se întâmplă dacă doriți să redați mai multe fișiere media, unul după altul? Pentru asta, aveți nevoie de o listă de redare.

Listele de redare pot fi create prin adăugarea mai multor MediaItems la player folosind addMediaItem. Acest lucru permite o redare fără întreruperi, iar tamponarea este gestionată în fundal, astfel încât utilizatorul nu vede o rotiță de tamponare atunci când schimbă elementele media.

  1. Adaugați următorul cod la 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ți cum se comportă comenzile playerului. Puteți utiliza 1f79fee4d082870f.pngși 39627002c03ce320.png pentru a naviga în secvența de elemente media.

7b5c034dafabe1bd.png

Captură de ecran: Controalele de redare care arată un buton următor și anterior

Este destul de util! Pentru mai multe informații, consultați documentația pentru dezvoltatori privind elementele media și listele de redare, precum și acest articol despre Playlist API.

Retransmisia adaptivă este o tehnică de transmitere media prin variația calității fluxului în funcție de lățimea de bandă disponibilă în rețea. Acest lucru permite utilizatorului să experimenteze media de cea mai bună calitate pe care o permite lățimea de bandă.

În mod obișnuit, același conținut media este împărțit în mai multe piste cu calități diferite (rate de biți și rezoluții). Playerul alege o piesă pe baza lățimii de bandă disponibile în rețea.

Care piesă este împărțită în bucăți de o anumită durată, de obicei între 2 și 10 secunde. Acest lucru permite playerului să treacă rapid de la o piesă la alta pe măsură ce se schimbă lățimea de bandă disponibilă. Jucătorul este responsabil de îmbinarea acestor bucăți pentru o redare fără întreruperi.

Selecția adaptivă a pieselor

În centrul fluxului adaptiv se află selectarea celei mai potrivite piese pentru mediul curent. Actualizați aplicația dvs. pentru a reda medii de streaming adaptiv utilizând selecția adaptivă a pieselor.

  1. Actualizați initializePlayer cu următorul cod:

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

În primul rând, creați un DefaultTrackSelector, care este responsabil pentru alegerea pieselor din elementul media. Apoi, spuneți-i lui trackSelector să aleagă numai piese cu definiție standard sau mai mică – o modalitate bună de a economisi datele utilizatorului în detrimentul calității. În cele din urmă, treceți trackSelector la constructorul dumneavoastră, astfel încât să fie utilizat la construirea instanței SimpleExoPlayer.

Constituiți un MediaItem adaptiv

DASH este un format de streaming adaptiv utilizat pe scară largă. Pentru a difuza conținut DASH, trebuie să creați un MediaItem ca mai înainte. Cu toate acestea, de data aceasta, trebuie să folosim un MediaItem.Builder în loc de fromUri.

Acest lucru se datorează faptului că fromUri utilizează extensia de fișier pentru a determina formatul media subiacent, dar URI-ul nostru DASH nu are o extensie de fișier, astfel încât trebuie să furnizăm un tip MIME de APPLICATION_MPD atunci când construim MediaItem.

  1. Actualizați initializePlayer după cum urmează:

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. Reporniți aplicația și vedeți streamingul video adaptiv cu DASH în acțiune. Este destul de ușor cu ExoPlayer!

Alte formate de streaming adaptiv

HLS (MimeTypes.APPLICATION_M3U8) și SmoothStreaming (MimeTypes.APPLICATION_SS) sunt alte formate de streaming adaptiv utilizate în mod obișnuit, ambele fiind acceptate de ExoPlayer. Pentru mai multe informații despre construirea altor surse media adaptive, consultați aplicația demo ExoPlayer.

În pașii anteriori, ați învățat cum să transmiteți fluxuri media progresive și adaptive. ExoPlayer face o mulțime de muncă pentru dvs. în spatele scenei, inclusiv următoarele:

  • Alocarea memoriei
  • Descărcarea fișierelor din container
  • Extragerea metadatelor din container
  • Decodificarea datelor
  • Rendarea video, audio și text pe ecran și pe difuzoare

Câteodată, este util să știți ce face ExoPlayer în timpul execuției pentru a înțelege și îmbunătăți experiența de redare pentru utilizatorii dvs.

De exemplu, este posibil să doriți să reflectați modificările stării de redare în interfața cu utilizatorul făcând următoarele:

  • Afișarea unui rotitor de încărcare atunci când playerul intră într-o stare de tamponare
  • Afișarea unei suprapuneri cu opțiuni de „urmărire următoare” atunci când piesa s-a încheiat

ExoPlayer oferă mai multe interfețe de ascultare care oferă callback-uri pentru evenimente utile. Folosiți un ascultător pentru a consemna în ce stare se află playerul.

Ascultați

  1. Declarați un membru privat de tip PlaybackStateListener în PlayerActivity.
  2. Creați o constantă TAG, pe care o folosiți ulterior pentru logare.

PlayerActivity.java

private PlaybackStateListener playbackStateListener;private static final String TAG = PlayerActivity.class.getName();
  1. Instanțiațializați playbackStateListener la începutul lui onCreate (nu se va compila încă, dar veți rezolva acest lucru în scurt timp).

PlayerActivity.java

@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_player); playbackStateListener = new PlaybackStateListener();
  1. Utilizați Quick Fix pentru a crea automat clasa interioară PlaybackStateListener.

b59ce69a22595ba7.png

Scenează: Meniul Quick Fix pentru crearea unei clase lipsă

  1. Implementați interfața Player.EventListener. Aceasta este utilizată pentru a vă informa cu privire la evenimentele importante ale playerului, inclusiv erori și modificări ale stării de redare.
  2. Înlocuiți onPlaybackStateChanged adăugând următorul cod:

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 este apelată atunci când se schimbă starea de redare. Noua stare este dată de parametrul playbackState.

Jucătorul se poate afla într-una din următoarele patru stări:

ExoPlayer.STATE_IDLE

ExoPlayer.STATE_READY

Stare

Descriere

Jucătorul a fost instanțiat, dar nu a fost încă pregătit.

ExoPlayer.STATE_BUFFERING

Jucătorul nu este capabil să joace din poziția curentă deoarece nu au fost stocate suficiente date în buffer.

Jucătorul este capabil să joace imediat din poziția curentă. Acest lucru înseamnă că playerul va începe automat redarea media dacă proprietatea playWhenReady a playerului este true. Dacă este false, playerul este în pauză.

ExoPlayer.STATE_ENDED

Jucătorul a terminat de redat conținutul media.

Înregistrează-ți ascultătorul

Pentru ca callback-urile tale să fie apelate, trebuie să îți înregistrezi playbackStateListener cu playerul. Faceți acest lucru în initializePlayer.

  1. Înregistrați ascultătorul înainte ca redarea să fie pregătită.

PlayerActivity.java

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

Încă o dată, trebuie să faceți ordine pentru a evita referințele suspendate de la player care ar putea cauza o scurgere de memorie.

  1. Îndepărtați ascultătorul din releasePlayer:

PlayerActivity.java

private void releasePlayer() { if (player != null) { player.removeListener(playbackStateListener); player.release(); player = null; }}
  1. Deschideți logcat și rulați aplicația.
  2. Utilizați controalele UI pentru a căuta, întrerupe și relua redarea. Ar trebui să vedeți schimbarea stării de redare în jurnale.

Aprofundați

ExoPlayer oferă o serie de alți ascultători, care sunt utili pentru a înțelege experiența de redare a utilizatorului. Există ascultători pentru audio și video, precum și un AnalyticsListener, care conține callback-urile de la toți ascultătorii. Unele dintre cele mai importante metode sunt următoarele:

  • onRenderedFirstFrame este apelată atunci când este redat primul cadru al unui videoclip. Cu ajutorul acesteia, puteți calcula cât timp a trebuit să aștepte utilizatorul pentru a vedea un conținut semnificativ pe ecran.
  • onDroppedVideoFrames este apelată atunci când cadrele video au fost abandonate. Cadrele scăpate indică faptul că redarea este janky și este probabil ca experiența utilizatorului să fie slabă.
  • onAudioUnderrun este apelat atunci când a avut loc un underrun audio. Underrun-urile cauzează erori audibile în sunet și sunt mai vizibile decât cadrele video pierdute.

AnalyticsListener poate fi adăugat la player cu addAnalyticsListener. Există metode corespunzătoare și pentru ascultătorii audio și video.

Gândiți-vă la ce evenimente sunt importante pentru aplicația dvs. și pentru utilizatori. Pentru mai multe informații, consultați Ascultarea evenimentelor playerului. Asta e tot pentru ascultătorii de evenimente!

Până acum, ați folosit PlayerControlView de la ExoPlayer pentru a afișa un controler de redare pentru utilizator.

bcfe17eebcad9e13.png

Captură de ecran: Controler de redare implicit

Ce se întâmplă dacă doriți să schimbați funcționalitatea sau aspectul acestor controale? Din fericire, aceste controale sunt foarte ușor de personalizat.

Prima personalizare simplă este să nu folosiți deloc controlerul. Acest lucru se poate face cu ușurință prin utilizarea atributului use_controller pe elementul PlayerView din interiorul activity_player.xml.

  1. Setați use_controller la false și controlul nu mai apare:

activity_player.xml

  1. Adaugați următorul namespace la FrameLayout:

activity_player.xml

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

Încercați-l acum.

Personalizați comportamentul

PlayerControlView are mai multe atribute care îi afectează comportamentul. Utilizați show_timeout, fastforward_increment și rewind_increment pentru a personaliza comportamentul controlerului.

  1. Îndepărtați app:use_controller="false".
  2. Modificați vizualizarea jucătorului pentru a utiliza show_timeout, fastforward_increment și 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"/>
  • Valoarea show_timeout indică PlayerView întârzierea în milisecunde înainte ca controlul să fie ascuns după ce utilizatorul a interacționat ultima dată cu el.
  • Valorile fastforward_increment și rewind_increment îi spun playerului timpul în milisecunde pentru a sări înainte sau înapoi atunci când utilizatorul atinge butoanele de derulare rapidă înainte sau înapoi.

Atributele lui PlayerControlView pot fi, de asemenea, setate programatic.

Personalizarea aspectului

Ei bine, acesta este un bun început. Dar ce se întâmplă dacă doriți ca PlayerControlView să aibă un aspect diferit sau să schimbați ce butoane sunt afișate? Implementarea lui PlayerControlView nu presupune că există butoane, așa că este ușor să le eliminați și să adăugați altele noi.

Vezi cum poți personaliza PlayerControlView.

  1. Creați un nou fișier layout custom_player_control_view.xml în folderul player-lib/res/layout/.
  2. Din meniul contextual al folderului layout, alegeți New – Layout resource file și numiți-l custom_player_control_view.xml.

ae1e3795726d4e4e.png

Captură de ecran: A fost creat fișierul layout pentru vizualizarea controlului jucătorului.

  1. Copiați fișierul layout original de aici în custom_player_control_view.xml.
  2. Îndepărtați elementele ImageButton cu id-ul @id/exo_prev și @id/exo_next.

Pentru a utiliza aspectul personalizat, trebuie să setați atributul app:controller_layout_id al elementului PlayerView din fișierul activity_player.xml.

  1. Utilizați ID-ul de aspect al fișierului personalizat ca în următorul fragment de cod:

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. Remăriți din nou aplicația. Vizualizarea de control a jucătorului nu mai are butoanele anterior și următor.

89e6535a22c8e321.png

Captură de ecran: Vizualizare personalizată a controlului playerului fără butoane anterior sau următor

Puteți aplica orice modificări doriți în fișierul de aspect. În mod implicit, sunt alese culorile temei Android. Puteți suprascrie acest lucru pentru a se potrivi cu designul aplicației dumneavoastră.

  1. Adaugați un atribut android:tint la fiecare element ImageButton:

custom_player_control_view.xml

<ImageButton android:id="@id/exo_rew" android:tint="#FF00A6FF" style="@style/ExoMediaButton.Rewind"/>
  1. Schimbați toate atributele android:textColor pe care le găsiți în fișierul dvs. personalizat la aceeași culoare: #FF00A6FF.

custom_player_control_control_view.xml

<TextView android:id="@id/exo_position" android:textColor="#FF00A6FF"/><TextView android:id="@id/exo_duration" android:textColor="#FF00A6FF"/>
  1. Rulați aplicația. Acum aveți componente UI frumoase și colorate!

e9835d65d6dd0634.png

Captură de ecran: Butoane colorate și vizualizarea textului

Înlocuiți stilul implicit

Ai creat doar un fișier de aspect personalizat și ați făcut referire la el folosind controller_layout_id în activity_player.xml.

O altă abordare este de a înlocui fișierul de aspect implicit pe care îl folosește PlayerControlView. Codul sursă al PlayerControlView ne spune că utilizează R.layout.exo_player_control_view pentru aspect. Dacă creăm propriul nostru fișier de aspect cu același nume de fișier, PlayerControlView utilizează în schimb fișierul dvs. în locul acestuia.

  1. Îndepărtați atributul controller_layout_id pe care tocmai l-ați adăugat.
  2. Ștergeți fișierul custom_player_control_view.xml.

Filmul PlayerView din activity_player.xml ar trebui să arate acum astfel:

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ți un fișier numit exo_player_control_view.xml în folderul res/layout din modulul de bibliotecă player-lib.
  2. Inserați următorul cod în exo_player_control_view.xml pentru a adăuga un buton de redare, un buton de pauză și un ImageView cu 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>
<?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>

Aceasta demonstrează modul în care puteți adăuga propriile elemente aici și le puteți amesteca cu elementele de control standard. ExoPlayerView utilizează acum controlul dvs. personalizat și toată logica de ascundere și afișare la interacțiunea cu controlul este păstrată.

Felicitări! Ați învățat multe despre integrarea ExoPlayer cu aplicația dumneavoastră.

Învățați mai multe

.

Lasă un răspuns

Adresa ta de email nu va fi publicată.