Medie-streaming med ExoPlayer

4ec261ee5a0bd0cc.png

Skærmbillede: YouTube Android-appen

ExoPlayer er en medieafspiller på app-niveau, der er bygget oven på medie-API’er på lavt niveau i Android. ExoPlayer har en række fordele i forhold til den indbyggede MediaPlayer i Android. Den understøtter mange af de samme medieformater som MediaPlayer samt adaptive formater, såsom DASH og SmoothStreaming. ExoPlayer kan i høj grad tilpasses og udvides, hvilket gør den i stand til mange avancerede brugssituationer. Det er et open source-projekt, der bruges af Google-apps, herunder YouTube og Google Play Movies & TV.

Forudsætninger

  • Moderat kendskab til Android-udvikling og Android Studio

Hvad du skal gøre

  • Opret en SimpleExoPlayerinstans, som forbereder og afspiller medier fra en række forskellige kilder.
  • Integrer ExoPlayer med appens aktivitetslivscyklus for at understøtte baggrunds-, forgrunds- og genoptagelse af afspilning i et enkelt- eller flervinduemiljø.
  • Brug MediaItems til at oprette en afspilningsliste.
  • Afspil adaptive videostreams, som tilpasser mediekvaliteten til den tilgængelige båndbredde.
  • Registrér hændelseslyttere til at overvåge afspilningstilstanden, og vis, hvordan lyttere kan bruges til at måle kvaliteten af afspilningen.
  • Brug standard ExoPlayer UI-komponenter, og tilpas dem derefter til din app’s stil.

Det skal du bruge

  • Android Studio version 3.5 eller højere
  • En Android-enhed med JellyBean (4.1) eller højere, ideelt set med Nougat (7.1) eller højere, da den understøtter flere vinduer.

Hent koden

For at komme i gang skal du downloade Android Studio-projektet:

Download zip

Alternativt kan du klone GitHub-repositoriet:

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

Katalogstruktur

Kloning eller udpakning giver dig en rodmappe (exoplayer-intro), som indeholder en mappe for hvert trin i dette codelab, sammen med alle de ressourcer, du har brug for:

/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

Mapperne exoplayer-codelab-N (hvor N er 00 til 04) indeholder den ønskede sluttilstand for hvert trin i dette codelab. Det er selvstændige Android Studio-projekter, som hver især kan importeres.

Importer det oprindelige projekt

  1. Start Android Studio.
  2. Vælg fil > Ny > Importer projekt*.*
  3. Importer det oprindelige projekt fra exoplayer-codelab-00.

f2e5feb9ade6c7f7.png

Skærmbillede: Projektstruktur ved import

Når opbygningen er afsluttet, vises to moduler: app-modulet (af typen program) og player-lib-modulet (af typen bibliotek). Modulet app er faktisk tomt, idet det kun har et manifest. Alt fra player-lib-modulet bliver slået sammen, når appen bygges ved hjælp af en gradle-afhængighed i app/build.gradle.

app/build.gradle

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

Din medieafspilleraktivitet bliver gemt i player-lib-modulet. Grunden til at holde den i et separat biblioteksmodul er, at du kan dele den mellem APK’er, der er rettet mod forskellige platforme, f.eks. mobil og Android TV. Det giver dig også mulighed for at drage fordel af funktioner som f.eks. dynamisk levering, som gør det muligt at installere din medieafspilningsfunktion kun, når brugeren har brug for den.

  1. Deploy og kør appen for at kontrollere, at alt er i orden. Appen skal fylde skærmen med en sort baggrund.

21c0dae6245fbd31.png

Skærmbillede: Blank app kører

Føj ExoPlayer-afhængighed til

ExoPlayer er et open source-projekt, der er hostet på GitHub. Hver udgivelse distribueres gennem jCenter, som er et af de standardpakkeopbevaringssteder, der bruges af Android Studio og Gradle. Hver udgivelse er entydigt identificeret ved en streng med følgende format:

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

Du kan tilføje ExoPlayer til dit projekt ved blot at importere dets klasser og brugergrænsefladekomponenter. Det er ret lille, idet det har et skrumpet fodaftryk på omkring 70-300 kB afhængigt af de inkluderede funktioner og understøttede formater. ExoPlayer-biblioteket er opdelt i moduler for at give udviklere mulighed for kun at importere den funktionalitet, de har brug for. Du kan finde flere oplysninger om ExoPlayers modulære struktur under Tilføj ExoPlayer-moduler.

  1. Åbn build.gradle-filen for player-lib-modulet.
  2. Føj følgende linjer til dependencies-afsnittet, og synkroniser projektet.

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

Føj PlayerView-elementet

  1. Åbn layoutressourcefilen activity_player.xml fra player-lib modulet.
  2. Placér markøren inde i FrameLayout-elementet.
  3. Begynd at skrive <PlayerView, og lad Android Studio autokomplettere PlayerView-elementet.
  4. Brug match_parent til width og height.
  5. Deklarér id’et som 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"/>

Fremadrettet henviser du til dette brugergrænsefladeelement som videovisningen.

  1. I PlayerActivity skal du nu finde videovisningen, så du kan opsætte den korrekt i onCreate-metoden i aktiviteten.

PlayerActivity.java

@Overrideprotected void onCreate(Bundle savedInstanceState) { playerView = findViewById(R.id.video_view);}
  1. Føj medlemsfeltet playerView til din PlayerActivity-klasse. Sørg for, at visningstypen er PlayerView.

Bemærk: Brug Quick Fix-funktionen i Android Studio til at tilføje et medlemsfelt automatisk. Husk at indstille typen til

PlayerView

i stedet for standard

View

b0f7f70115bb90e5.png

Screenshot: Hurtigrettelsesmenu til oprettelse af et medlemsfelt

Opret en ExoPlayer

For at afspille streamingmedier skal du bruge et ExoPlayer-objekt. Den enkleste måde at oprette et på er at bruge SimpleExoPlayer.Builder-klassen. Som navnet antyder, bruger den builder-mønsteret til at oprette en SimpleExoPlayer-instans.

SimpleExoPlayer er en praktisk, universel implementering af ExoPlayer-grænsefladen.

Føj en privat metode initializePlayer til at oprette din SimpleExoPlayer.

PlayerActivity.java

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

Opret en SimpleExoPlayer.Builder ved hjælp af din kontekst, og kald derefter build for at oprette dit SimpleExoPlayer-objekt. Dette tildeles derefter til player, som du skal deklarere som et medlemsfelt. Du bruger derefter playerView.setPlayer til at binde player til den tilsvarende visning.

Opret et medieelement

Din player skal nu have noget indhold til afspilning. Til dette opretter du et MediaItem. Der findes mange forskellige typer MediaItem, men du starter med at oprette en til en MP3-fil på internettet.

Den enkleste måde at oprette en MediaItem på er ved at bruge MediaItem.fromUri, som accepterer URI’en for en mediefil. Tilføj MediaItem til player ved hjælp af player.setMediaItem.

  1. Føj følgende kode til initializePlayer:

PlayerActivity.java

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

Bemærk, at R.string.media_url_mp3 er defineret som https://storage.googleapis.com/exoplayer-test-media-0/play.mp3 i strings.xml.

Spil med Activity-livscyklus

Vores player kan beslaglægge en masse ressourcer, herunder hukommelse, CPU, netværksforbindelser og hardwarecodecs. Mange af disse ressourcer er en mangelvare, især for hardware-codecs, hvor der måske kun er ét. Det er vigtigt, at du frigiver disse ressourcer til andre apps, så de kan bruge dem, når du ikke bruger dem, f.eks. når din app sættes i baggrunden.

Sagt på en anden måde bør din afspillers livscyklus være bundet til din app’ livscyklus. For at implementere dette skal du overskrive de fire metoder i PlayerActivity: onStart, onResume, onPause og onStop.

  1. Med PlayerActivity åben skal du klikke på Code menu > Override methods….
  2. Vælg onStart, onResume, onPause og onStop.
  3. Initialisér afspilleren i onStart eller onResume callback afhængigt af API-niveauet.

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-niveau 24 og højere understøtter flere vinduer. Da din app kan være synlig, men ikke aktiv i split window-tilstand, skal du initialisere afspilleren i onStart. Android API-niveau 24 og lavere kræver, at du venter så længe som muligt, indtil du får fat i ressourcer, så du venter til onResume, før du initialiserer afspilleren.

  1. Føj metoden hideSystemUi til.

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 er en hjælpemetode, der kaldes i onResume, og som giver dig mulighed for at få en fuldskærmsoplevelse.

  1. Frikøb ressourcer med releasePlayer (som du opretter om kort tid) i onPause og 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(); }}

Med API-niveau 24 og lavere er der ingen garanti for, at onStop bliver kaldt, så du skal frigive spilleren så tidligt som muligt i onPause. Med API-niveau 24 og højere (som bragte multi- og split-window-tilstand) er det garanteret, at onStop bliver kaldt. I den pausede tilstand er din aktivitet stadig synlig, så du venter med at frigive spilleren til onStop.

Du skal nu oprette en releasePlayer-metode, som frigør spillerens ressourcer og destruerer den.

  1. Føj følgende kode til aktiviteten:

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

Hvor du frigiver og ødelægger afspilleren, skal du gemme følgende oplysninger:

  • Play/pause-status ved hjælp af getPlayWhenReady.
  • Aktuel afspilningsposition ved hjælp af getCurrentPosition.
  • Aktuel vinduesindeks ved hjælp af getCurrentWindowIndex. Du kan finde flere oplysninger om vinduer under Tidslinje.

Dette giver dig mulighed for at genoptage afspilningen fra det sted, hvor brugeren slap. Det eneste, du skal gøre, er at levere disse tilstandsoplysninger, når du initialiserer din afspiller.

Slutforberedelse

Det eneste, du skal gøre nu, er at levere de tilstandsoplysninger, du gemte i releasePlayer, til din afspiller under initialiseringen.

  1. Føj følgende til initializePlayer:

PlayerActivity.java

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

Her er, hvad der sker:

  • setPlayWhenReady fortæller afspilleren, om den skal starte afspilningen, så snart alle ressourcer til afspilning er blevet erhvervet. Da playWhenReady oprindeligt er true, starter afspilningen automatisk, første gang appen køres.
  • seekTo fortæller afspilleren, at den skal søge til en bestemt position i et bestemt vindue. Både currentWindow og playbackPosition er initialiseret til nul, så afspilningen starter helt fra starten, første gang appen køres.
  • prepare fortæller afspilleren, at den skal erhverve alle de ressourcer, der er nødvendige for afspilningen.

Afspilning af lyd

Endeligt er du færdig! Start appen for at afspille MP3-filen og se det indlejrede kunstværk.

1d049aead0483777.png

Skærmbillede: Appen afspiller et enkelt nummer.

Test aktivitetslivscyklus

Test, om appen fungerer i alle de forskellige tilstande i aktivitetslivscyklusen.

  1. Start en anden app, og sæt din app i forgrunden igen. Genoptages den i den korrekte position?
  2. Pause appen, og flyt den til baggrunden og derefter til forgrunden igen. Holder den fast i en pauseret tilstand, når den er sat i baggrunden i pauseret tilstand?
  3. Rotér appen. Hvordan opfører den sig, hvis du ændrer orienteringen fra portræt til landskab og tilbage?

Afspil video

Hvis du ønsker at afspille video, er det lige så nemt som at ændre medieelementets URI til en MP4-fil.

  1. Ændre URI’en i initializePlayer til R.string.media_url_mp4.
  2. Start appen igen, og test adfærden efter at være blevet afspillet i baggrunden med videoafspilning også.

PlayerActivity.java

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

Den PlayerView gør det hele. I stedet for kunstværket gengives videoen i fuld skærm.

4ebd0b0f98593691.png

Skærmbillede: Appen afspiller video.

Du rocker! Du har lige oprettet en app til streaming af medier i fuld skærm på Android, komplet med livscyklusstyring, gemt tilstand og brugergrænsefladekontroller!

Din nuværende app afspiller en enkelt mediefil, men hvad hvis du ønsker at afspille flere mediefiler efter hinanden? Til det har du brug for en afspilningsliste.

Playlister kan oprettes ved at tilføje flere MediaItems til din player ved hjælp af addMediaItem. Dette giver mulighed for problemfri afspilning, og buffering håndteres i baggrunden, så brugeren ikke ser en bufferingsspinner, når der skiftes medieelementer.

  1. Føj følgende kode til initializePlayer:

PlayerActivity.java

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

Kontroller, hvordan afspillerkontrollerne opfører sig. Du kan bruge 1f79fee4d082870f.pngog 39627002c03ce320.png til at navigere i sekvensen af medieelementer.

7b5c034dafabe1bd.png

Skærmbillede: Afspilningskontroller viser en næste og forrige knap

Det er ret praktisk! Du kan finde flere oplysninger i udviklerdokumentationen om medieelementer og afspilningslister og i denne artikel om API’et for afspilningslister.

Adaptiv streaming er en teknik til streaming af medier ved at variere streamens kvalitet på baggrund af den tilgængelige netværksbåndbredde. Dette giver brugeren mulighed for at opleve medierne i den bedste kvalitet, som deres båndbredde tillader.

Typisk er det samme medieindhold opdelt i flere spor med forskellige kvaliteter (bitfrekvenser og opløsninger). Afspilleren vælger et spor ud fra den tilgængelige netværksbåndbredde.

Hvert spor er opdelt i bidder af en given varighed, typisk mellem 2 og 10 sekunder. Dette giver afspilleren mulighed for hurtigt at skifte mellem sporene, efterhånden som den tilgængelige båndbredde ændrer sig. Afspilleren er ansvarlig for at sætte disse stykker sammen for at sikre en problemfri afspilning.

Adaptivt sporvalg

Det centrale i adaptiv streaming er at vælge det mest passende spor til det aktuelle miljø. Opdater din app til afspilning af adaptive streamingmedier ved hjælp af adaptivt sporvalg.

  1. opdatér initializePlayer med følgende kode:

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

Opret først en DefaultTrackSelector, som er ansvarlig for at vælge spor i medieelementet. Fortæl derefter din trackSelector, at den kun skal vælge spor med standardopløsning eller lavere – en god måde at spare på brugerens data på bekostning af kvaliteten. Til sidst skal du videregive din trackSelector til din builder, så den bruges, når du bygger SimpleExoPlayer-instansen.

Byg et adaptivt MediaItem

DASH er et udbredt adaptivt streamingformat. Hvis du vil streame DASH-indhold, skal du oprette en MediaItem som før. Denne gang skal vi dog bruge en MediaItem.Builder i stedet for fromUri.

Dette skyldes, at fromUri bruger filudvidelsen til at bestemme det underliggende medieformat, men vores DASH-URI har ikke en filudvidelse, så vi skal angive en MIME-type på APPLICATION_MPD, når vi konstruerer MediaItem.

  1. Opdatér initializePlayer på følgende måde:

PlayerActivity.java

  1. Start appen igen, og se adaptiv videostreaming med DASH i aktion. Det er ret nemt med ExoPlayer!

Andre adaptive streamingformater

HLS (MimeTypes.APPLICATION_M3U8) og SmoothStreaming (MimeTypes.APPLICATION_SS) er andre almindeligt anvendte adaptive streamingformater, som begge understøttes af ExoPlayer. Du kan finde flere oplysninger om opbygning af andre adaptive mediekilder i ExoPlayer-demo-appen.

I de foregående trin lærte du, hvordan du streamer progressive og adaptive mediestrømme. ExoPlayer udfører en masse arbejde for dig bag kulisserne, herunder følgende:

  • Allokering af hukommelse
  • Hentning af containerfiler
  • Udtrækning af metadata fra containeren
  • Dekodning af data
  • Gengivelse af video, lyd og tekst til skærmen og højttalerne

Sommetider er det nyttigt at vide, hvad ExoPlayer gør ved kørselstid for at forstå og forbedre afspilningsoplevelsen for dine brugere.

Du kan f.eks. ønske at afspejle ændringer i afspilningstilstanden i brugergrænsefladen ved at gøre følgende:

  • Vise en loading spinner, når afspilleren går i en bufferingtilstand
  • Vise et overlay med “se næste” muligheder, når sporet er slut

ExoPlayer tilbyder flere lyttergrænseflader, der leverer callbacks for nyttige hændelser. Du bruger en lytter til at logge, hvilken tilstand afspilleren befinder sig i.

Lyt op

  1. Deklarér et privat medlem af typen PlaybackStateListener i PlayerActivity.
  2. Opret en TAG-konstant, som du bruger til logning senere.

PlayerActivity.java

private PlaybackStateListener playbackStateListener;private static final String TAG = PlayerActivity.class.getName();
  1. Instantiér playbackStateListener i begyndelsen af onCreate (det kompileres ikke endnu, men du retter det om kort tid).

PlayerActivity.java

@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_player); playbackStateListener = new PlaybackStateListener();
  1. Brug Quick Fix til automatisk at oprette den indre klasse PlaybackStateListener.

b59ce69a22595ba7.png

Screenshot: Quick Fix-menuen til oprettelse af en manglende klasse

    1. Implementer Player.EventListenergrænsefladen. Dette bruges til at informere dig om vigtige afspillerbegivenheder, herunder fejl og ændringer i afspilningstilstanden.
    2. Override onPlaybackStateChanged ved at tilføje følgende kode:

    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 kaldes, når afspilningstilstanden ændres. Den nye tilstand angives af parameteren playbackState.

    Afspilleren kan være i en af følgende fire tilstande:

    State

    Description

    ExoPlayer.STATE_IDLE

    Afspilleren er blevet instantieret, men er endnu ikke blevet forberedt.

    ExoPlayer.STATE_BUFFERING

    Spilleren er ikke i stand til at spille fra den aktuelle position, fordi der ikke er blevet gemt nok data i buffer.

    ExoPlayer.STATE_READY

    Spilleren er i stand til straks at spille fra den aktuelle position. Det betyder, at afspilleren automatisk begynder at afspille medierne, hvis afspillerens playWhenReady-egenskab er true. Hvis den er false, sættes afspilleren på pause.

    ExoPlayer.STATE_ENDED

    Afspilleren er færdig med at afspille mediet.

    Registrer din lytter

    For at få dine callbacks kaldt, skal du registrere din playbackStateListener hos afspilleren. Det skal du gøre i initializePlayer.

    1. Registrer lytteren, før afspilningen forberedes.

    PlayerActivity.java

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

    Også her skal du rydde op for at undgå dinglende referencer fra afspilleren, som kan forårsage en hukommelseslækage.

    1. Fjern lytteren i releasePlayer:

    PlayerActivity.java

    private void releasePlayer() { if (player != null) { player.removeListener(playbackStateListener); player.release(); player = null; }}
    1. Åbn logcat, og kør appen.
    2. Brug brugergrænsefladekontrollerne til at søge, sætte afspilningen på pause og genoptage den. Du bør kunne se, at afspilningstilstanden ændres i logfilerne.

    Gå dybere

    ExoPlayer tilbyder en række andre lyttere, som er nyttige til at forstå brugerens afspilningsoplevelse. Der er lyttere til lyd og video samt en AnalyticsListener, som indeholder callbacks fra alle lytterne. Nogle af de vigtigste metoder er følgende:

    • onRenderedFirstFrame kaldes, når den første frame i en video gengives. Hermed kan du beregne, hvor lang tid brugeren måtte vente på at se meningsfuldt indhold på skærmen.
    • onDroppedVideoFrames kaldes, når videoframes er blevet droppet. Droppede frames er tegn på, at afspilningen er skramlet, og at brugeroplevelsen sandsynligvis vil være dårlig.
    • onAudioUnderrun kaldes, når der er sket en lydunderkørsel. Underrunner forårsager hørbare glitches i lyden og er mere mærkbare end tabte videoframes.

    AnalyticsListener kan tilføjes til player med addAnalyticsListener. Der er også tilsvarende metoder til lyd- og videolytterne.

    Tænk over, hvilke hændelser der er vigtige for din app og dine brugere. Du kan finde flere oplysninger under Lytte til afspillerbegivenheder. Det var det med hændelseslytterne!

    Så langt har du brugt ExoPlayer’s PlayerControlView til at vise en afspilningscontroller til brugeren.

    bcfe17eebcad9e13.png

    Screenshot: Standard afspilningscontroller

    Hvad sker der, hvis du ønsker at ændre funktionaliteten eller udseendet af disse kontroller? Heldigvis kan disse kontroller i høj grad tilpasses.

    Den første enkle tilpasning er, at du slet ikke bruger controlleren. Dette kan nemt gøres ved at bruge attributten use_controllerPlayerView-elementet inde i activity_player.xml.

  1. Sæt use_controller til false, og kontrolelementet vises ikke længere:

activity_player.xml

<com.google.android.exoplayer2.ui.PlayerView app:use_controller="false"/>
  1. Føj følgende namespace til din FrameLayout:

activity_player.xml

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

Prøv det nu.

Apas adfærden

PlayerControlView har flere attributter, der påvirker dens adfærd. Brug show_timeout, fastforward_increment og rewind_increment til at tilpasse controllerens adfærd.

  1. Fjern app:use_controller="false".
  2. Ændre spillervisningen, så den bruger show_timeout, fastforward_increment og 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"/>
  • Værdien show_timeout fortæller PlayerView forsinkelsen i millisekunder, før kontrollen skjules, efter at brugeren sidst har interageret med den.
  • Værdierne fastforward_increment og rewind_increment fortæller afspilleren, hvor lang tid i millisekunder der skal springes fremad eller tilbage, når brugeren trykker på knapperne til at spole fremad eller tilbage.

Den PlayerControlViews attributter kan også indstilles programmatisk.

Anpas udseendet

Det er en god start. Men hvad nu, hvis du vil have PlayerControlView til at se anderledes ud eller ændre, hvilke knapper der vises? Implementeringen af PlayerControlView forudsætter ikke, at der findes nogen knapper, så det er nemt at fjerne dem og tilføje nye.

Se på, hvordan du kan tilpasse PlayerControlView.

  1. Opret en ny layoutfil custom_player_control_view.xml i mappen player-lib/res/layout/.
  2. I kontekstmenuen i layoutmappen skal du vælge Ny – Layoutressourcefil og navngive den custom_player_control_view.xml.

ae1e3795726d4e4e.png

Skærmbillede: Layoutfilen til afspillerkontrolvisningen er blevet oprettet.

  1. Kopier den oprindelige layoutfil herfra til custom_player_control_view.xml.
  2. Fjern ImageButton-elementerne med id @id/exo_prev og @id/exo_next.

For at bruge dit brugerdefinerede layout skal du indstille attributten app:controller_layout_id for PlayerView-elementet i activity_player.xml-filen.

  1. Brug layout-id’et for din brugerdefinerede fil som i følgende kodestump:

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. Start appen igen. Kontrolvisningen for spilleren har ikke længere knapperne forrige og næste.

89e6535a22c8e321.png

Skærmbillede: Brugerdefineret afspillerkontrolvisning uden knapperne forrige og næste

Du kan anvende alle de ændringer, du ønsker, i layoutfilen. Som standard er farverne i Android-temaet valgt. Du kan tilsidesætte dette, så det passer til designet i din app.

  1. Føj en android:tint-attribut til hvert ImageButton-element:

custom_player_control_view.xml

<ImageButton android:id="@id/exo_rew" android:tint="#FF00A6FF" style="@style/ExoMediaButton.Rewind"/>
  1. Opnå alle android:textColor-attributter, du finder i din brugerdefinerede fil, til den samme farve: #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. Kør appen. Nu har du smukke, farvede UI-komponenter!

e9835d65d6dd0634.png

Skærmbillede: Du har lige oprettet en brugerdefineret layoutfil og refereret til den ved hjælp af controller_layout_id i activity_player.xml.

En anden fremgangsmåde er at tilsidesætte standardlayoutfilen, som PlayerControlView bruger. Kildekoden for PlayerControlView fortæller os, at den bruger R.layout.exo_player_control_view til layout. Hvis du opretter vores egen layoutfil med samme filnavn, bruger PlayerControlView din fil i stedet.

  1. Fjern den controller_layout_id-attribut, du lige har tilføjet.
  2. Slet filen custom_player_control_view.xml.

Den PlayerView i activity_player.xml skal nu se sådan ud:

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. Opret en fil med navnet exo_player_control_view.xml i res/layout-mappen i dit biblioteksmodul player-lib.
  2. Indsæt følgende kode i exo_player_control_view.xml for at tilføje en afspilningsknap, en pauseknap og en ImageView med et 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>

Dette demonstrerer, hvordan du kan tilføje dine egne elementer her og blande dem med standardkontrolelementer. ExoPlayerView bruger nu din brugerdefinerede kontrol, og al logik til at skjule og vise, når du interagerer med kontrollen, er bevaret.

Godt tillykke! Du har lært en masse om integration af ExoPlayer i din app.

Lær mere

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.