如何使用Media3(搭配ExoPlayer + MediaSessionService)?基于Media3实现MediaSessionService搭建简易音频播放应用遇阻求助
Hey there! Let me walk you through building a minimal audio playback app with Media3's ExoPlayer and MediaSessionService step by step — I’ve struggled with the sparse docs too, so I’ll keep this as straightforward as possible.
1. Add Media3 Dependencies
First, add the necessary Media3 libraries to your app-level build.gradle (or build.gradle.kts):
dependencies { // Media3 core components implementation "androidx.media3:media3-exoplayer:1.2.1" implementation "androidx.media3:media3-session:1.2.1" implementation "androidx.media3:media3-common:1.2.1" }
(Note: Use the latest version number instead of 1.2.1 if available)
2. Implement the MediaSessionService
Create a custom service that extends MediaSessionService — this is the core of your media session handling:
import android.content.Intent import androidx.media3.common.MediaItem import androidx.media3.common.Player import androidx.media3.exoplayer.ExoPlayer import androidx.media3.session.MediaSession import androidx.media3.session.MediaSessionService class MyMediaSessionService : MediaSessionService() { private lateinit var player: ExoPlayer private lateinit var mediaSession: MediaSession override fun onCreate() { super.onCreate() // Initialize ExoPlayer with proper audio attributes player = ExoPlayer.Builder(this).build() player.setAudioAttributes( androidx.media3.common.AudioAttributes.Builder() .setContentType(androidx.media3.common.C.AUDIO_CONTENT_TYPE_MUSIC) .setUsage(androidx.media3.common.C.USAGE_MEDIA) .build(), true ) // Link ExoPlayer to MediaSession mediaSession = MediaSession.Builder(this, player).build() // Handle core playback commands via session callback mediaSession.setCallback(object : MediaSession.Callback { override fun onPlay() { player.play() // Start foreground service to avoid being killed on Android 8.0+ startForeground(1, androidx.core.app.NotificationCompat.Builder(this@MyMediaSessionService, "media_playback_channel") .setContentTitle("Now Playing") .setSmallIcon(R.drawable.ic_music_note) .setStyle(androidx.media3.session.MediaStyleNotificationHelper.MediaStyle(mediaSession)) .build() ) } override fun onPause() { player.pause() stopForeground(STOP_FOREGROUND_REMOVE) } override fun onAddMediaItems( mediaSession: MediaSession, controller: MediaSession.ControllerInfo, mediaItems: MutableList<MediaItem> ): MediaSession.MediaItemsHolder { // Replace with your actual audio URI (local file or remote URL) val updatedItems = mediaItems.map { it.buildUpon().setUri("https://example.com/your-audio-file.mp3").build() } return MediaSession.MediaItemsHolder(updatedItems) } }) } override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? { return mediaSession } override fun onDestroy() { mediaSession.release() player.release() super.onDestroy() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { return START_STICKY } }
Key Takeaways:
- Audio attributes ensure proper handling of audio focus (e.g., pausing when a call comes in).
- The foreground service is mandatory for background playback on newer Android versions.
- The callback bridges user commands (play/pause) to ExoPlayer actions.
3. Configure the Service in AndroidManifest.xml
Don’t forget to register your service and add required permissions:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" /> <uses-permission android:name="android.permission.INTERNET" /> <!-- Required for remote audio --> <application ...> <service android:name=".MyMediaSessionService" android:foregroundServiceType="mediaPlayback" android:exported="true"> <intent-filter> <action android:name="androidx.media3.session.MediaSessionService" /> </intent-filter> </service> </application>
(Note: For Android 8.0+, you’ll need to create a notification channel — add this snippet to your app’s Application class or initial activity)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( "media_playback_channel", "Media Playback", NotificationManager.IMPORTANCE_LOW ) getSystemService(NotificationManager::class.java).createNotificationChannel(channel) }
4. Build a Minimal UI Activity
Create a simple activity with play/pause buttons to control playback via MediaController:
import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.media3.session.MediaController import androidx.media3.session.SessionToken import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.MoreExecutors import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { private lateinit var controllerFuture: ListenableFuture<MediaController> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Connect to the MediaSessionService val sessionToken = SessionToken(this, ComponentName(this, MyMediaSessionService::class.java)) controllerFuture = MediaController.Builder(this, sessionToken).buildAsync() controllerFuture.addListener({ val controller = controllerFuture.get() // Link buttons to controller commands btn_play.setOnClickListener { controller.play() } btn_pause.setOnClickListener { controller.pause() } // Add your audio media item to the queue controller.addMediaItem(MediaItem.fromUri("https://example.com/your-audio-file.mp3")) }, MoreExecutors.directExecutor()) } override fun onDestroy() { MediaController.releaseFuture(controllerFuture) super.onDestroy() } }
The corresponding layout (activity_main.xml) only needs two buttons with IDs btn_play and btn_pause.
Common Troubleshooting Tips
- Service not connecting? Double-check the
SessionTokenuses the correct service class name, and the manifest intent-filter is set properly. - Audio not playing? Verify your audio URI is valid, and you’ve added the
INTERNETpermission for remote files. - Foreground notification missing? Ensure you’ve created the required notification channel for Android 8.0+.
- Player crashing on release? Make sure you only call
player.release()in the service’sonDestroy()method, not elsewhere.
That’s it! This should give you a working minimal audio app with Media3’s ExoPlayer and MediaSessionService. Let me know if you hit any specific snags — I’m happy to help debug further.
内容的提问来源于stack exchange,提问作者max




