Medien im Hintergrund abspielen

Sie können Medien im Hintergrund abspielen, auch wenn Ihre App nicht auf dem Display angezeigt wird, z. B. wenn der Nutzer mit anderen Apps interagiert.

Dazu betten Sie den MediaPlayer in einen MediaBrowserServiceCompat-Dienst ein und lassen ihn mit einem MediaBrowserCompat in einer anderen Aktivität interagieren.

Seien Sie bei der Implementierung dieser Client- und Serverkonfiguration vorsichtig. Es gibt Erwartungen, wie ein Player, der in einem Hintergrunddienst ausgeführt wird, mit dem Rest des Systems interagiert. Wenn Ihre Anwendung diese Erwartungen nicht erfüllt, kann die Nutzererfahrung beeinträchtigt werden. Weitere Informationen finden Sie unter Audio-Apps erstellen.

Auf dieser Seite werden spezielle Anweisungen zum Verwalten eines MediaPlayers beschrieben, wenn du ihn in einem Dienst implementierst.

Asynchron ausführen

Wie bei einem Activity werden auch bei einem Service standardmäßig alle Aufgaben in einem einzigen Thread ausgeführt. Wenn Sie eine Aktivität und einen Dienst aus derselben Anwendung ausführen, verwenden sie standardmäßig denselben Thread (den „Hauptthread“).

Dienste müssen eingehende Intents schnell verarbeiten und dürfen bei der Beantwortung keine langen Berechnungen ausführen. Alle zeitaufwendigen Aufgaben oder blockierenden Aufrufe müssen asynchron ausgeführt werden: entweder über einen anderen Thread, den Sie selbst implementieren, oder mithilfe der vielen Funktionen des Frameworks für die asynchrone Verarbeitung.

Wenn du beispielsweise MediaPlayer aus deinem Hauptthread verwendest, solltest du Folgendes beachten:

Beispiel:

Kotlin

private const val ACTION_PLAY: String = "com.example.action.PLAY"

class MyService: Service(), MediaPlayer.OnPreparedListener {

    private var mMediaPlayer: MediaPlayer? = null

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        ...
        val action: String = intent.action
        when(action) {
            ACTION_PLAY -> {
                mMediaPlayer = ... // initialize it here
                mMediaPlayer?.apply {
                    setOnPreparedListener(this@MyService)
                    prepareAsync() // prepare async to not block main thread
                }

            }
        }
        ...
    }

    /** Called when MediaPlayer is ready */
    override fun onPrepared(mediaPlayer: MediaPlayer) {
        mediaPlayer.start()
    }
}

Java

public class MyService extends Service implements MediaPlayer.OnPreparedListener {
    private static final String ACTION_PLAY = "com.example.action.PLAY";
    MediaPlayer mediaPlayer = null;

    public int onStartCommand(Intent intent, int flags, int startId) {
        ...
        if (intent.getAction().equals(ACTION_PLAY)) {
            mediaPlayer = ... // initialize it here
            mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.prepareAsync(); // prepare async to not block main thread
        }
    }

    /** Called when MediaPlayer is ready */
    public void onPrepared(MediaPlayer player) {
        player.start();
    }
}

Asynchrone Fehler behandeln

Bei synchronen Vorgängen werden Fehler mit einer Ausnahme oder einem Fehlercode signalisiert. Wenn Sie jedoch asynchrone Ressourcen verwenden, sollten Sie Ihre Anwendung über Fehler entsprechend informieren. Bei einer MediaPlayer implementieren Sie einen MediaPlayer.OnErrorListener und legen ihn in Ihrer MediaPlayer-Instanz fest:

Kotlin

class MyService : Service(), MediaPlayer.OnErrorListener {

    private var mediaPlayer: MediaPlayer? = null

    fun initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer?.setOnErrorListener(this)
    }

    override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

Java

public class MyService extends Service implements MediaPlayer.OnErrorListener {
    MediaPlayer mediaPlayer;

    public void initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer.setOnErrorListener(this);
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

Wenn ein Fehler auftritt, wechselt die MediaPlayer in den Status Error. Sie müssen sie dann zurücksetzen, bevor Sie sie wieder verwenden können. Weitere Informationen finden Sie im vollständigen Zustandsdiagramm für die Klasse MediaPlayer.

Wakelocks verwenden

Wenn Sie Musik im Hintergrund abspielen oder streamen, müssen Sie Wakelocks verwenden, um zu verhindern, dass das System die Wiedergabe stört, z. B. durch das Einschlafen des Geräts.

Ein Wakelock ist ein Signal an das System, dass Ihre Anwendung Funktionen verwendet, die auch dann verfügbar sein sollten, wenn das Smartphone inaktiv ist.

Damit die CPU weiter ausgeführt wird, während MediaPlayer wiedergegeben wird, rufe die Methode setWakeMode() auf, wenn du MediaPlayer initialisierst. Mit der Taste MediaPlayer wird die angegebene Sperre während der Wiedergabe aufrechterhalten und bei einer Pause oder einem Stopp aufgehoben:

Kotlin

mediaPlayer = MediaPlayer().apply {
    // ... other initialization here ...
    setWakeMode(applicationContext, PowerManager.PARTIAL_WAKE_LOCK)
}

Java

mediaPlayer = new MediaPlayer();
// ... other initialization here ...
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

Die in diesem Beispiel erworbene Wakelock sorgt jedoch nur dafür, dass die CPU aktiv bleibt. Wenn Sie Medien über das Netzwerk streamen und WLAN verwenden, sollten Sie auch eine WifiLock halten, die Sie manuell erwerben und freigeben müssen. Wenn Sie also mit der Vorbereitung der MediaPlayer mit der Remote-URL beginnen, sollten Sie die WLAN-Sperre erstellen und erwerben.

Beispiel:

Kotlin

val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiLock: WifiManager.WifiLock =
    wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock")

wifiLock.acquire()

Java

WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
    .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");

wifiLock.acquire();

Wenn du die Medien pausierst oder beendest oder das Netzwerk nicht mehr benötigst, solltest du die Sperre aufheben:

Kotlin

wifiLock.release()

Java

wifiLock.release();

Bereinigung ausführen

Wie bereits erwähnt, kann ein MediaPlayer-Objekt erhebliche Systemressourcen beanspruchen. Sie sollten es daher nur so lange beibehalten, wie Sie es benötigen, und release() aufrufen, wenn Sie es nicht mehr benötigen. Es ist wichtig, diese Bereinigungsmethode explizit aufzurufen, anstatt sich auf die Systembereinigung zu verlassen. Es kann nämlich einige Zeit dauern, bis der Garbage Collector die MediaPlayer wiederverwendet, da er nur auf den Speicherbedarf und nicht auf den Mangel an anderen medienbezogenen Ressourcen reagiert. Wenn Sie also einen Dienst verwenden, sollten Sie die Methode onDestroy() immer überschreiben, damit MediaPlayer freigegeben wird:

Kotlin

class MyService : Service() {

    private var mediaPlayer: MediaPlayer? = null
    // ...

    override fun onDestroy() {
        super.onDestroy()
        mediaPlayer?.release()
    }
}

Java

public class MyService extends Service {
   MediaPlayer mediaPlayer;
   // ...

   @Override
   public void onDestroy() {
       super.onDestroy();
       if (mediaPlayer != null) mediaPlayer.release();
   }
}

Außer beim Herunterfahren sollten Sie immer nach anderen Möglichkeiten suchen, Ihre MediaPlayer freizugeben. Wenn du beispielsweise davon ausgehst, dass du über einen längeren Zeitraum keine Medien abspielen kannst (z. B. wenn der Audiofokus verloren geht), solltest du deine vorhandene MediaPlayer aufheben und später noch einmal erstellen. Wenn Sie die Wiedergabe jedoch nur für eine sehr kurze Zeit unterbrechen möchten, sollten Sie die MediaPlayer beibehalten, um den Aufwand für das Erstellen und Vorbereiten zu vermeiden.

Weitere Informationen

Jetpack Media3 ist die empfohlene Lösung für die Medienwiedergabe in Ihrer App. Weitere Informationen

Auf diesen Seiten finden Sie Themen zum Aufzeichnen, Speichern und Abspielen von Audio- und Videoinhalten: