Skip to content

在 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 是简化视频播放的控件,内部封装了 MediaPlayerSurfaceView

示例代码:播放本地视频
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. 注意事项

  1. 权限管理:动态请求 READ_EXTERNAL_STORAGEREAD_MEDIA_* 权限。
  2. 生命周期控制:在 onPause()onStop() 中暂停播放,避免资源浪费。
  3. 网络请求:播放网络资源时需添加 <uses-permission android:name="android.permission.INTERNET" />
  4. 格式兼容性
    • MediaPlayerVideoView 对格式支持有限(依赖设备解码器)。
    • ExoPlayer 支持更广泛的格式(需添加扩展依赖,如 exoplayer-hls)。
  5. 后台播放:若需后台播放音频,需使用 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、高级控制)。
  • 关键优化:异步加载、生命周期管理、错误监听、缓冲提示。