Medien im Hintergrund abspielen

Sie können Medien im Hintergrund abspielen, auch wenn Ihre Anwendung nicht auf dem Bildschirm angezeigt wird, z. B. während der Nutzer mit anderen Anwendungen 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 vorsichtig bei der Implementierung dieser Client- und Servereinstellungen. 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 das zu einer negativen Nutzererfahrung führen. Weitere Informationen finden Sie unter Audio-App erstellen.

Auf dieser Seite werden spezielle Anleitungen für die Verwaltung eines MediaPlayer beschrieben, wenn Sie ihn in einem Dienst implementieren.

Asynchron ausführen

Wie bei einem Activity wird standardmäßig die gesamte Arbeit in einem Service in einem einzelnen 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 Antwort darauf keine zeitaufwendigen Berechnungen durchführen. Alle rechenintensiven oder blockierenden Aufrufe müssen asynchron ausgeführt werden, entweder über einen anderen Thread, den Sie selbst implementieren, oder über die zahlreichen Framework-Funktionen für die asynchrone Verarbeitung.

Wenn Sie beispielsweise MediaPlayer über Ihren Hauptthread verwenden, sollten Sie Folgendes tun:

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 durch eine Ausnahme oder einen Fehlercode signalisiert. Wenn Sie jedoch asynchrone Ressourcen verwenden, sollten Sie Ihre Anwendung entsprechend über Fehler informieren. Bei einem MediaPlayer implementieren Sie ein MediaPlayer.OnErrorListener und legen es 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 MediaPlayer in den Status Fehler. Du musst das Gerät zurücksetzen, bevor du es wieder verwenden kannst. 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 Wake Locks verwenden, um zu verhindern, dass das System die Wiedergabe beeinträchtigt, z. B. indem das Gerät in den Ruhemodus wechselt.

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 während der Wiedergabe Ihres MediaPlayer weiter ausgeführt wird, rufen Sie die Methode setWakeMode() auf, wenn Sie Ihr MediaPlayer initialisieren. Das MediaPlayer behält die angegebene Sperre während der Wiedergabe bei und gibt sie bei einer Pause oder beim Stoppen frei:

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

Das 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 wahrscheinlich auch einen WifiLock beibehalten, den Sie manuell abrufen und freigeben müssen. Wenn Sie also mit der Vorbereitung des MediaPlayer mit der Remote-URL beginnen, sollten Sie das WLAN-Schloss erstellen und abrufen.

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 Sie die Wiedergabe von Medien pausieren oder beenden oder das Netzwerk nicht mehr benötigen, sollten Sie die Sperre aufheben:

Kotlin

wifiLock.release()

Java

wifiLock.release();

Bereinigung durchführen

Wie bereits erwähnt, kann ein MediaPlayer-Objekt eine erhebliche Menge an Systemressourcen beanspruchen. Sie sollten es daher nur so lange behalten, 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 automatische Speicherbereinigung des Systems zu verlassen, da es einige Zeit dauern kann, bis die automatische Speicherbereinigung die MediaPlayer freigibt. Sie reagiert nämlich nur auf den Speicherbedarf und nicht auf den Mangel an anderen mediabezogenen Ressourcen. Wenn Sie einen Dienst verwenden, sollten Sie die Methode onDestroy() immer überschreiben, um sicherzustellen, dass Sie die MediaPlayer freigeben:

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

Du solltest immer auch nach anderen Möglichkeiten suchen, dein MediaPlayer zu entladen, außer wenn es heruntergefahren wird. Wenn Sie beispielsweise davon ausgehen, dass Sie über einen längeren Zeitraum keine Medien abspielen können (z. B. nach dem Verlust des Audiofokus), sollten Sie Ihr vorhandenes MediaPlayer auf jeden Fall freigeben und später neu erstellen. Wenn Sie die Wiedergabe nur für kurze Zeit unterbrechen möchten, sollten Sie Ihr MediaPlayer wahrscheinlich behalten, um den Aufwand für die erneute Erstellung und Vorbereitung zu vermeiden.

Weitere Informationen

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

Auf diesen Seiten werden Themen im Zusammenhang mit der Aufnahme, Speicherung und Wiedergabe von Audio- und Videoinhalten behandelt: