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
- Ce veți face
- De ce aveți nevoie
- Obțineți codul
- Structura directoarelor
- Importă proiectul inițial
- app/build.gradle
- Add ExoPlayer dependency
- player-lib/build.gradle
- Adaugați elementul PlayerView
- activity_player.xml
- PlayerActivity.java
- Crearea unui ExoPlayer
- PlayerActivity.java
- Crearea unui element media
- PlayerActivity.java
- Jucând frumos cu ciclul de viață al Activității
- PlayerActivity.java
- PlayerActivity.java
- PlayerActivity.java
- PlayerActivity.java
- Pregătire finală
- PlayerActivity.java
- Reducere audio
- Testați ciclul de viață al activității
- Play video
- PlayerActivity.java
- PlayerActivity.java
- Selecția adaptivă a pieselor
- PlayerActivity.java
- Constituiți un MediaItem adaptiv
- PlayerActivity.java
- Alte formate de streaming adaptiv
- Ascultați
- PlayerActivity.java
- PlayerActivity.java
- PlayerActivity.java
- Înregistrează-ți ascultătorul
- PlayerActivity.java
- PlayerActivity.java
- Aprofundați
- activity_player.xml
- activity_player.xml
- Personalizați comportamentul
- activity_player.xml
- Personalizarea aspectului
- activity_player.xml
- custom_player_control_view.xml
- custom_player_control_control_view.xml
- Înlocuiți stilul implicit
- activity_player.xml
- exo_player**_control_view.xml**
- Învățați mai multe
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
MediaItem
s 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
- Pornește Android Studio.
- Alege File > New > Import Project*.*
- Importă proiectul inițial din
exoplayer-codelab-00
.
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.
- 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.
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.
- Deschideți fișierul
build.gradle
al modululuiplayer-lib
. - 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
- Deschideți fișierul de resurse layout
activity_player.xml
din modululplayer-lib
. - Puneți cursorul în interiorul elementului
FrameLayout
. - Începeți să tastați
<PlayerView
și lăsați Android Studio să autocompleteze elementulPlayerView
. - Utilizați
match_parent
pentruwidth
șiheight
. - 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.
- În
PlayerActivity
, acum trebuie să găsiți vizualizarea video, astfel încât să o puteți configura corect în metodaonCreate
a activității.
PlayerActivity.java
@Overrideprotected void onCreate(Bundle savedInstanceState) { playerView = findViewById(R.id.video_view);}
- Adaugați câmpul membru
playerView
la clasaPlayerActivity
. Asigurați-vă că tipul de vizualizare estePlayerView
.
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
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
.
- 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
.
- Cu
PlayerActivity
deschis, faceți clic pe meniul Code > Override methods…. - Selectați
onStart
,onResume
,onPause
șionStop
. - Inițializați playerul în callback-ul
onStart
sauonResume
, î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.
- 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.
- Liberați resursele cu
releasePlayer
(pe care o creați în scurt timp) înonPause
șionStop
.
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.
- 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.
- 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. DeoareceplayWhenReady
este inițialtrue
, 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âtcurrentWindow
, cât șiplaybackPosition
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ă.
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.
- Porniți o altă aplicație și puneți din nou aplicația dvs. în prim-plan. Se reia în poziția corectă?
- 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ă?
- 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.
- Modificați URI-ul din
initializePlayer
înR.string.media_url_mp4
. - 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.
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 MediaItem
s 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.
- 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 și pentru a naviga în secvența de elemente media.
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.
- 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
.
- 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);}
- 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
- Declarați un membru privat de tip
PlaybackStateListener
înPlayerActivity
. - 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();
- Instanțiațializați
playbackStateListener
la începutul luionCreate
(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();
- Utilizați Quick Fix pentru a crea automat clasa interioară
PlaybackStateListener
.
Scenează: Meniul Quick Fix pentru crearea unei clase lipsă
- 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. - Î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:
Stare |
Descriere |
Jucătorul a fost instanțiat, dar nu a fost încă pregătit. |
|
|
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 |
|
|
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
.
- Î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.
- Îndepărtați ascultătorul din
releasePlayer
:
PlayerActivity.java
private void releasePlayer() { if (player != null) { player.removeListener(playbackStateListener); player.release(); player = null; }}
- Deschideți logcat și rulați aplicația.
- 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.
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
.
- Setați
use_controller
lafalse
și controlul nu mai apare:
activity_player.xml
- 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.
- Îndepărtați
app:use_controller="false"
. - Modificați vizualizarea jucătorului pentru a utiliza
show_timeout
,fastforward_increment
șirewind_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
șirewind_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
.
- Creați un nou fișier layout
custom_player_control_view.xml
în folderulplayer-lib/res/layout/
. - Din meniul contextual al folderului layout, alegeți New – Layout resource file și numiți-l
custom_player_control_view.xml
.
Captură de ecran: A fost creat fișierul layout pentru vizualizarea controlului jucătorului.
- Copiați fișierul layout original de aici în
custom_player_control_view.xml
. - Î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
.
- 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"/>
- Remăriți din nou aplicația. Vizualizarea de control a jucătorului nu mai are butoanele anterior și următor.
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ă.
- Adaugați un atribut
android:tint
la fiecare elementImageButton
:
custom_player_control_view.xml
<ImageButton android:id="@id/exo_rew" android:tint="#FF00A6FF" style="@style/ExoMediaButton.Rewind"/>
- 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"/>
- Rulați aplicația. Acum aveți componente UI frumoase și colorate!
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.
- Îndepărtați atributul
controller_layout_id
pe care tocmai l-ați adăugat. - Ș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"/>
- Creați un fișier numit
exo_player_control_view.xml
în folderulres/layout
din modulul de bibliotecăplayer-lib
. - Inserați următorul cod în
exo_player_control_view.xml
pentru a adăuga un buton de redare, un buton de pauză și unImageView
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
.