在 Android 中播放多媒体文件(如音频、视频)是常见的功能需求。以下是详细的实现方法、关键类和 Kotlin 示例代码,涵盖本地文件、网络资源播放、进度控制等核心功能。
1. 添加权限
在 AndroidManifest.xml
中添加以下权限:
xml
<!-- 网络权限(播放网络资源时需添加) -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 读取存储权限(播放本地文件时需添加) -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Android 13+ 的媒体权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
2. 播放音频
使用 MediaPlayer
类
MediaPlayer
是 Android 原生提供的音频播放器,支持本地和网络音频。
示例代码:播放本地音频
kotlin
class AudioPlayerActivity : AppCompatActivity() {
private lateinit var mediaPlayer: MediaPlayer
private var isPrepared = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_audio_player)
// 初始化 MediaPlayer
mediaPlayer = MediaPlayer().apply {
setDataSource("/sdcard/Music/sample.mp3") // 本地文件路径
setOnPreparedListener {
isPrepared = true
start() // 自动播放
}
prepareAsync() // 异步准备(避免阻塞主线程)
}
// 控制按钮
findViewById<Button>(R.id.btnPlay).setOnClickListener {
if (isPrepared && !mediaPlayer.isPlaying) mediaPlayer.start()
}
findViewById<Button>(R.id.btnPause).setOnClickListener {
if (mediaPlayer.isPlaying) mediaPlayer.pause()
}
findViewById<Button>(R.id.btnStop).setOnClickListener {
mediaPlayer.stop()
isPrepared = false
}
}
override fun onDestroy() {
mediaPlayer.release() // 释放资源
super.onDestroy()
}
}
播放网络音频
kotlin
val url = "https://example.com/audio.mp3"
mediaPlayer.apply {
setDataSource(url)
prepareAsync() // 必须异步准备网络资源
}
3. 播放视频
使用 VideoView
类
VideoView
是简化视频播放的控件,内部封装了 MediaPlayer
和 SurfaceView
。
示例代码:播放本地视频
kotlin
class VideoPlayerActivity : AppCompatActivity() {
private lateinit var videoView: VideoView
private lateinit var mediaController: MediaController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_video_player)
videoView = findViewById(R.id.videoView)
mediaController = MediaController(this).apply {
setAnchorView(videoView) // 绑定到 VideoView
}
// 设置视频路径
videoView.setVideoPath("/sdcard/Movies/sample.mp4")
videoView.setMediaController(mediaController)
videoView.start()
}
override fun onPause() {
videoView.pause()
super.onPause()
}
override fun onDestroy() {
videoView.stopPlayback()
super.onDestroy()
}
}
播放网络视频
kotlin
val videoUrl = "https://example.com/video.mp4"
videoView.setVideoURI(Uri.parse(videoUrl))
4. 使用 ExoPlayer(高级推荐)
ExoPlayer
是 Google 开源的媒体播放库,支持更多格式(如 HLS、DASH)、自定义渲染器和扩展功能。
步骤 1:添加依赖
在 build.gradle
中添加:
gradle
implementation "com.google.android.exoplayer:exoplayer:2.19.1"
步骤 2:播放视频示例
kotlin
class ExoPlayerActivity : AppCompatActivity() {
private lateinit var exoPlayer: SimpleExoPlayer
private lateinit var playerView: PlayerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_exo_player)
playerView = findViewById(R.id.playerView)
// 初始化 ExoPlayer
exoPlayer = SimpleExoPlayer.Builder(this).build()
playerView.player = exoPlayer
// 创建媒体源(支持本地、网络、HLS等)
val mediaItem = MediaItem.fromUri("https://example.com/video.m3u8")
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
exoPlayer.playWhenReady = true // 自动播放
}
override fun onPause() {
exoPlayer.pause()
super.onPause()
}
override fun onDestroy() {
exoPlayer.release()
super.onDestroy()
}
}
5. 关键功能扩展
进度控制(SeekBar)
kotlin
// 更新进度
val seekBar = findViewById<SeekBar>(R.id.seekBar)
exoPlayer.addListener(object : Player.Listener {
override fun onEvents(player: Player, events: Player.Events) {
seekBar.max = player.duration.toInt()
seekBar.progress = player.currentPosition.toInt()
}
})
// 拖动进度
seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if (fromUser) exoPlayer.seekTo(progress.toLong())
}
// 其他方法省略...
})
缓冲处理
kotlin
exoPlayer.addListener(object : Player.Listener {
override fun onPlaybackStateChanged(state: Int) {
when (state) {
Player.STATE_BUFFERING -> showLoading()
Player.STATE_READY -> hideLoading()
}
}
})
6. 注意事项
- 权限管理:动态请求
READ_EXTERNAL_STORAGE
或READ_MEDIA_*
权限。 - 生命周期控制:在
onPause()
或onStop()
中暂停播放,避免资源浪费。 - 网络请求:播放网络资源时需添加
<uses-permission android:name="android.permission.INTERNET" />
。 - 格式兼容性:
MediaPlayer
和VideoView
对格式支持有限(依赖设备解码器)。ExoPlayer
支持更广泛的格式(需添加扩展依赖,如exoplayer-hls
)。
- 后台播放:若需后台播放音频,需使用
Service
并获取AudioFocus
。
7. 完整布局示例
音频播放布局(activity_audio_player.xml)
xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btnPlay"
android:text="播放"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btnPause"
android:text="暂停"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btnStop"
android:text="停止"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
视频播放布局(activity_exo_player.xml)
xml
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/playerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:show_buffering="when_playing"
app:controller_layout_id="@layout/exo_player_control_view"/>
总结
- 简单场景:使用
MediaPlayer
(音频)或VideoView
(视频)。 - 复杂需求:选择
ExoPlayer
(支持自适应流、自定义 UI、高级控制)。 - 关键优化:异步加载、生命周期管理、错误监听、缓冲提示。