You can play media in the background even when your application is not on
screen, for example, while the user is interacting with other applications.

To do so, you embed the MediaPlayer in a [`MediaBrowserServiceCompat`](https://developer.android.com/reference/androidx/media/MediaBrowserServiceCompat)
service and have it interact with a [`MediaBrowserCompat`](https://developer.android.com/reference/android/support/v4/media/MediaBrowserCompat) in another
activity.

Be cautious with implementing this client and server setup. There are
expectations about how a player running in a background service interacts with
the rest of the system. If your application does not fulfill those expectations,
the user may have a bad experience. See [Building an Audio App](https://developer.android.com/guide/topics/media-apps/audio-app/building-an-audio-app) for details.

This page describes special instructions for managing a MediaPlayer when it you
implement it inside a service.

## Run asynchronously

Like an [`Activity`](https://developer.android.com/reference/android/app/Activity), all work in a [`Service`](https://developer.android.com/reference/android/app/Service) is done in a single thread
by default. In fact, when you run an activity and a service from the same
application, they use the same thread (the "main thread") by default.

Services must process incoming intents quickly and never perform lengthy
computations when responding to them. You must perform any heavy work or
blocking calls asynchronously: either from another thread you implement
yourself, or using the framework's many facilities for asynchronous processing.

For example, when you use [`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer) from your main thread, you should:

- Call [`prepareAsync()`](https://developer.android.com/reference/android/media/MediaPlayer#prepareAsync()) rather than [`prepare()`](https://developer.android.com/reference/android/media/MediaPlayer#prepare()), and
- Implement a [`MediaPlayer.OnPreparedListener`](https://developer.android.com/reference/android/media/MediaPlayer.OnPreparedListener) in order to be notified when the preparation is complete and you can start playing.

For example:  

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

### Handle asynchronous errors

On synchronous operations, errors are signaled with an exception or an error
code. When you use asynchronous resources, however, you should notify your
application of errors appropriately. In the case of a [`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer), you
implement a [`MediaPlayer.OnErrorListener`](https://developer.android.com/reference/android/media/MediaPlayer.OnErrorListener) and set it in your
[`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer) instance:  

### 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!
        }
    }

When an error occurs, the [`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer) moves to the *Error* state. must
reset it before you can use it again. For details, see the full state diagram
for the [`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer) class.

## Use wake locks

When you play or stream music in the background, you must use wake locks to
prevent the system from interfering with your playback, for example, by having
the device go to sleep.

A wake lock is a signal to the system that your application is using features
that should stay available even when the phone is idle.
| **Note:** You should always use wake locks sparingly and hold them only for as long as truly necessary, because they significantly reduce the battery life of the device.

To ensure that the CPU continues running while your [`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer) is
playing, call the [`setWakeMode()`](https://developer.android.com/reference/android/media/MediaPlayer#setWakeMode(android.content.Context,%20int)) method when you initialize your
[`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer). The [`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer) holds the specified lock while
playing and releases the lock when paused or stopped:  

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

However, the wake lock acquired in this example ensures only that the CPU
remains awake. If you are streaming media over the network and you are using
Wi-Fi, you probably want to hold a [`WifiLock`](https://developer.android.com/reference/android/net/wifi/WifiManager.WifiLock) as well, which you must
acquire and release manually. So, when you start preparing the
[`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer) with the remote URL, you should create and acquire the Wi-Fi
lock.

For example:  

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

When you pause or stop your media, or when you no longer need the
network, you should release the lock:  

### Kotlin

    wifiLock.release()

### Java

    wifiLock.release();

## Perform cleanup

As mentioned earlier, a [`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer) object can consume a significant
amount of system resources, so you should keep it only for as long as you need
and call [`release()`](https://developer.android.com/reference/android/media/MediaPlayer#release()) when you are done with it. It's important to call
this cleanup method explicitly rather than rely on system garbage collection
because it might take some time before the garbage collector reclaims the
[`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer), as it's only sensitive to memory needs and not to shortage
of other media-related resources. So, in the case when you're using a service,
you should always override the [`onDestroy()`](https://developer.android.com/reference/android/app/Service#onDestroy()) method to make sure you are
releasing the [`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer):  

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

You should always look for other opportunities to release your
[`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer) as well, apart from releasing it when being shut down. For
example, if you expect not to be able to play media for an extended period of
time (after losing audio focus, for example), you should definitely release your
existing [`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer) and create it again later. On the other hand, if you
only expect to stop playback for a very short time, you should probably hold on
to your [`MediaPlayer`](https://developer.android.com/reference/android/media/MediaPlayer) to avoid the overhead of creating and preparing it
again.

## Learn more

Jetpack Media3 is the recommended solution for media playback in your app. [Read
more](https://developer.android.com/media/media3) about it.

These pages cover topics relating to recording, storing, and playing back audio
and video:

- [Supported Media Formats](https://developer.android.com/guide/topics/media/media-formats)
- [MediaRecorder](https://developer.android.com/guide/topics/media/mediarecorder)
- [Data Storage](https://developer.android.com/guide/topics/data/data-storage)