Ein praktisches Tutorial zu ExoPlayer

Als Android-Entwickler koenntest du Video-Wiedergabe in einer Jetpack Compose-Anwendung implementieren muessen. Ich war in der gleichen Situation, habe dieses Thema recherchiert und eine nette Loesung gefunden, die ich in diesem Tutorial praesentiere.

Bei der Recherche bin ich auf zwei Optionen gestossen:

  1. MediaPlayer und
  2. ExoPlayer

Ich habe mich fuer ExoPlayer entschieden, weil er flexibler und funktionsreicher zu sein schien. Er scheint auch weiter verbreitet zu sein, sodass ich mehr Beispiele und Diskussionen finden konnte.

Es gibt viele Tutorials, aber selbst neuere verwenden manchmal veralteten Code. Ich habe diese als Ausgangspunkt genommen und die veralteten Teile aktualisiert, dann unnoetige Stuecke entfernt, um eine minimale funktionierende Loesung zu produzieren.

Das Ergebnis ist eine aktuelle, voll funktionsfaehige Jetpack Compose-App, die eine Video-URL nimmt und das Video in der App anzeigt.

Lass uns mit der Erstellung eines neuen Projekts in Android Studio beginnen und waehle “Empty Compose Activity”.

Fuelle die notwendigen Felder fuer die neue Anwendung aus.

Fuege zuerst die ExoPlayer-Abhaengigkeit in der build.gradle hinzu:

implementation 'com.google.android.exoplayer:exoplayer:2.18.1'

Als Naechstes habe ich ein Composable namens VideoView erstellt, das den gesamten ExoPlayer-bezogenen Code kapselt.

@Composable
fun VideoView(videoUri: String) {
 val context = LocalContext.current
 
 val exoPlayer = ExoPlayer.Builder(LocalContext.current)
 .build()
 .also { exoPlayer ->
   val mediaItem = MediaItem.Builder()
   .setUri(videoUri)
   .build()
   exoPlayer.setMediaItem(mediaItem)
   exoPlayer.prepare()
  }
 
 DisposableEffect(
  AndroidView(factory = {
   StyledPlayerView(context).apply {
    player = exoPlayer
   }
  })
 ) {
  onDispose { exoPlayer.release() }
 }
}

Schauen wir uns diesen Code genauer an.

Es gibt vier Punkte zu erwaehnen:

  1. Richte die ExoPlayer-Instanz exoPlayer ein, indem du ExoPlayer.Builder aufrufst und den aktuellen LocalContext bereitstellst.
  2. Erstelle das mediaItem aus der Video-URI mit MediaItem.Builder().
  3. Erstelle einen DisposableEffect, der zwei Dinge tut: Wenn das Composable angezeigt wird, erstellt es die StyledPlayerView und weist den exoPlayer zu; wenn die View disposed wird, gibt sie den exoPlayer frei.

Bitte schau im Ressourcenabschnitt am Ende dieses Artikels nach Links zu Jetpack Compose Side Effects, insbesondere DisposableEffect.

Aendere jetzt MainActivity, um VideoView zu verwenden. Das Endergebnis sieht so aus:

class MainActivity: ComponentActivity() {
 override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContent {
   VideoApplicationTheme {
    Surface(
     modifier = Modifier.fillMaxSize(),
     color = MaterialTheme.colors.background
    ) {
     VideoView(videoUri = "https://storage.googleapis.com/exoplayer-test-media-0/BigBuckBunny_320x180.mp4")
    }
   }
  }
 }
}

Du kannst auch die Vorschau wie folgt aktualisieren:

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
 VideoApplicationTheme {
  VideoView(videoUri = "https://storage.googleapis.com/exoplayer-test-media-0/BigBuckBunny_320x180.mp4")
 }
}

Alles ist an Ort und Stelle, um die App zu starten. Warte!

Fast alles - wenn du versuchst, die App so auszufuehren, bekommst du eine Exception:

E/LoadTask: Unexpected exception loading stream
  java.lang.SecurityException: Permission denied (missing INTERNET permission?)
  at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:150)
 ...

Da das Video aus dem Internet geladen wird, benoetigt die App Internet-Berechtigung.

Fuege die folgende Zeile zur AndroidManifest.xml hinzu (unter app/manifests):

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

Die Datei sieht dann so aus:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.mycompany.videoapplication">
 
 <uses-permission android:name="android.permission.INTERNET"></uses-permission>
 
 <application
  android:allowBackup="true"
  android:icon="@mipmap/ic_launcher"
  android:label="@string/app_name"
  android:roundIcon="@mipmap/ic_launcher_round"
  android:supportsRtl="true"
  android:theme="@style/Theme.VideoApplication">
  <activity
   android:name=".MainActivity"
   android:exported="true"
   android:label="@string/app_name"
   android:theme="@style/Theme.VideoApplication">
   <intent-filter>
    <action android:name="android.intent.action.MAIN" />
 
    <category android:name="android.intent.category.LAUNCHER" />
   </intent-filter>
  </activity>
 </application>
 
</manifest>

Starte die App und du solltest das Video sehen, das wie unten gezeigt abgespielt wird.

Hoffentlich hat alles funktioniert.

Wie versprochen, hier sind einige Konfigurationsoptionen, die du nuetzlich finden koenntest:

  1. Video automatisch starten
  2. Steuerelemente ausblenden
  3. Video wiederholen
  4. Seitenverhaeltnis aendern

Starte das Video automatisch nach dem Laden der View mit:

exoPlayer.playWhenReady = true

Um die Player-Steuerelemente auszublenden, fuege diese Zeilen zum StyledPlayerView-Setup hinzu:

StyledPlayerView(context).apply {
 hideController()
 useController = false
 
 player = exoPlayer
}

Konfiguriere den Player, um das Video unendlich zu wiederholen:

exoPlayer.repeatMode = Player.REPEAT_MODE_ALL

Um das Seitenverhaeltnis zu aendern (zum Beispiel, um das Video zu fuellen und in die View zu beschneiden):

exoPlayer.videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING

Ich hoffe, dieses Tutorial war hilfreich.

Danke fuers Lesen!

Ressourcen