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:
- Rufen Sie
prepareAsync()anstelle vonprepare()an und - Implementieren Sie ein
MediaPlayer.OnPreparedListener, um benachrichtigt zu werden, wenn die Vorbereitung abgeschlossen ist und Sie mit dem Spielen beginnen können.
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: