Android中如何利用Timer配合Fragment播放指定时长背景音乐
嘿,这个需求我之前做类似功能时碰到过,拆解开来分几步就搞定了,我给你详细说说:
实现步骤拆解
1. 先准备好音频资源
把你那10秒的背景音乐放到项目的res/raw目录下(如果没有raw目录就自己新建一个),比如命名为bg_task_music.mp3,Android支持常见的MP3、WAV等格式,放心用。
2. 音频播放的核心逻辑(用MediaPlayer足够)
对于短音频场景,用系统自带的MediaPlayer就够了,不用搞复杂的ExoPlayer。关键是要和Fragment的生命周期绑定,避免内存泄漏:
首先在Fragment里声明MediaPlayer变量:
private var mediaPlayer: MediaPlayer? = null
然后在Fragment的视图创建完成后初始化MediaPlayer:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 直接用create方法初始化,自动加载raw目录下的音频资源 mediaPlayer = MediaPlayer.create(requireContext(), R.raw.bg_task_music) // 设置音频播放完成的回调,方便后续清理 mediaPlayer?.setOnCompletionListener { player -> player.reset() // 重置播放器,避免下次播放出问题 } // 可选:监听播放错误,防止崩溃 mediaPlayer?.setOnErrorListener { _, errorCode, _ -> Log.e("TaskMusic", "音频播放出错,错误码:$errorCode") true // 返回true表示我们自己处理了错误 } }
记得在Fragment销毁视图的时候释放资源,这步千万不能忘,否则会内存泄漏:
override fun onDestroyView() { super.onDestroyView() mediaPlayer?.let { player -> if (player.isPlaying) player.stop() player.release() // 释放所有资源 mediaPlayer = null // 置空避免引用 } }
3. 同步任务与音频播放
假设你的10秒任务是耗时操作(比如数据处理、模拟任务),不能在主线程跑,推荐用Kotlin协程来处理,代码更简洁:
先写一个启动任务和音频的方法:
private fun startSyncTaskAndMusic() { // 先请求音频焦点(可选,但体验更好,避免和其他应用音频冲突) val audioManager = requireContext().getSystemService(Context.AUDIO_SERVICE) as AudioManager val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT) .setOnAudioFocusChangeListener { focusChange -> when (focusChange) { // 失去焦点就暂停播放 AudioManager.AUDIOFOCUS_LOSS -> mediaPlayer?.pause() // 重新获得焦点就继续播放 AudioManager.AUDIOFOCUS_GAIN -> mediaPlayer?.start() } } .build() // 请求到焦点再播放音频 if (audioManager.requestAudioFocus(focusRequest) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { mediaPlayer?.start() } // 启动10秒耗时任务,用协程在IO线程执行 viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { // 这里替换成你的实际任务,比如网络请求、文件解析等 delay(10000) // 模拟10秒任务 // 任务完成后切回主线程处理UI和音频 withContext(Dispatchers.Main) { // 停止音频(防止音频因为某些原因没自动结束) mediaPlayer?.let { if (it.isPlaying) it.stop() } // 释放音频焦点 audioManager.abandonAudioFocusRequest(focusRequest) // 任务完成后的UI提示,比如Toast或者更新界面 Toast.makeText(requireContext(), "任务和音频同步完成啦", Toast.LENGTH_SHORT).show() } } }
然后在需要触发的地方调用这个方法,比如Fragment里的按钮点击:
binding.btnStartTask.setOnClickListener { startSyncTaskAndMusic() }
4. 几个要注意的细节
- 时长一致性:确保你的任务时长和音频时长都是10秒,如果任务时长可能波动,可以改成监听音频播放完成的回调来结束任务,或者反过来根据任务结束时间停止音频。
- 内存泄漏:一定要在
onDestroyView里释放MediaPlayer,用viewLifecycleOwner的协程作用域,避免Fragment销毁后协程还在跑。 - 异常处理:MediaPlayer可能会因为资源不存在、权限问题等播放失败,记得加上错误监听,避免应用崩溃。
内容的提问来源于stack exchange,提问作者ss1234
相关产品推荐
相关产品推荐

