android 使用MediaPlayer实现音乐播放

        Android 多媒体框架支持播放各种常见媒体类型,因此 可轻松地将音频、视频和图片集成到您的应用中。你可以播放音频或 从存储在应用资源(原始资源)的媒体文件(原始资源)中获取独立文件 或从通过网络连接到达的数据流中,所有这些均使用 MediaPlayer API。

1. MediaPlayer初始化
  mMediaPlayer = MediaPlayer()mMediaPlayer?.let {it.setAudioStreamType(AudioManager.STREAM_MUSIC)it.setOnCompletionListener(this)it.setOnErrorListener(this)}

MediaPlayer初始化只需要直接创建即可,添加播放完成跟错误监听。一般我们初始化还可以首次将上次播放的音乐跟播放进度设置进去,mMediaPlayer?.setDataSource(music.data)是设置播放音乐数据,mMediaPlayer?.seekTo(lastMusicProgress)是设置播放进度,将播放进度设置到上次播放的位置

    private fun initMediaPlayer(position: Int = 0) = launchMain {val lastMusicProgress = LocalKV.getIns().getInt(Constant.LAST_PLAY_PROGRESS, 0)val music: Music = mPlayList[position]if (music.data != null) {try {mMediaPlayer?.reset()mMediaPlayer?.setDataSource(music.data)mMediaPlayer?.prepare()mMediaPlayer?.seekTo(lastMusicProgress)mLastMusic = music} catch (e: Exception) {LogUtil.i(TAG, "initMediaPlayer error=${e.message}")}}}
2. 播放音乐

如果是同一首歌而且只是暂停可以直接调用MediaPlayer?.start()继续播放,如果不是同一首歌需要重新调用mMediaPlayer?.setDataSource(it.data)设置播放音乐,然后再调用start去播放,如果该首音乐有问题可以直接播放下一首。

    fun play() {if (mMusicPosition >= mPlayList.size - 1) {mMusicPosition = mPlayList.size - 1LogUtil.i(TAG, "play position exceed music list")}mCurrentMusic = mPlayList[mMusicPosition]mCurrentMusic?.let {if (it.data == null) {return}if (isCurrentMusic(mCurrentMusic)) {if (mMediaPlayer?.isPlaying == true) {pause()} else {mMediaPlayer?.start()}} else {mMediaPlayer?.reset()val f = File(it.data)if (!f.exists()) {next()return}try {mMediaPlayer?.setDataSource(it.data)mMediaPlayer?.prepare()mMediaPlayer?.start()mLastMusic = mCurrentMusic} catch (e: Exception) {mLastMusic = nullnext()}}}}
3. 播放下一首实现

这里会增加播放模式的实现,一般播放模式是顺序、单曲循环、随机、列表循环,正常按顺序播放只需要将播放列表的位置加1即可,即播放下一首。随机就是将所有音乐数据进行随机生成一个数字当下标,然后播放该首音乐。

    fun next() {if (mPlayList.size <= 0) {Toast.makeText(mContext,"no music",Toast.LENGTH_SHORT).show()return}when (mPlayMode) {LIST_ONCE -> {mMusicPosition++if (mPlayMode >= mPlayList.size) {mMusicPosition = mPlayList.size} else {play()}}LIST_CYCLE, SINGLE_CYCLE -> {mMusicPosition++mMusicPosition = if (mMusicPosition >= mPlayList.size) 0 else mMusicPositionplay()}LIST_RAND -> {mMusicPosition = getRandomMusic()play()}}}/*** 设置随机position** @return*/private fun getRandomMusic(): Int {if (mPlayList.size <= 0) return 0if (isListRandNext) {return mMusicPosition + 1}val random = Random()return random.nextInt(mPlayList.size)}
4.实现上一首播放

播放上一首跟播放下一首类似,只是播放的位置减1即可。

  fun previous() {if (mPlayList.size <= 0) {Toast.makeText(mContext,“no music”,Toast.LENGTH_SHORT).show()LogUtil.i(TAG, "play music list is null")return}when (mPlayMode) {LIST_ONCE -> {mMusicPosition--if (mMusicPosition < 0) {mMusicPosition = 0LogUtil.i(TAG, "previous is already first music")} else {play()}}LIST_CYCLE -> {mMusicPosition--if (mMusicPosition <= 0) {mMusicPosition = mPlayList.size - 1}play()}SINGLE_CYCLE -> {if (isListRandNext) {mMusicPosition = mPlayList.size - 1} else {mMusicPosition--}if (mMusicPosition < 0) {mMusicPosition = mPlayList.size - 1}play()}LIST_RAND -> {mMusicPosition = getRandomMusic()play()}}}
5. 实现音乐播放暂停

MediaPlayer开始由Started状态变成Paused状态,先判断当前是否在播放,如果正在播放就调用

MediaPlayer.pause()去暂停当前音乐播放。

   /*** 暂停播放*/fun pause() {if (mPlayList.size <= 0) {LogUtil.i(TAG, "play music list is null")return}if (mMediaPlayer?.isPlaying == true) {mMediaPlayer?.pause()}}
6. 停止音乐播放

当调用stop方法时,MediaPlayer无论正处于Started、Paused、Prepared或PlaybackCompleted中的哪种状态,都将进入Stopped状态。一旦处于Stoped状态,playback将不能开始,直到重新调用prepare或prepareAsync函数,且处于Prepared状态时才可以开始。

   /*** 停止播放*/fun stop() {if (mPlayList.size <= 0) {LogUtil.i(TAG, "play music list is null")return}mMediaPlayer?.let {if (it.isPlaying) {it.stop()it.reset()mLastMusic = null}}}
7.设置播放速度
    /*** 设置播放速度* @param speed*/fun setPlaySpeed(speed: Float) {mMediaPlayer?.let {if (it.isPlaying) {try {it.playbackParams = it.playbackParams.setSpeed(speed)} catch (e: Exception) {next()}}}}
8. 释放资源

当我们不需要播放或者退出的时候可以调用mMediaPlayer?.release()去释放资源

   /*** 释放*/fun release() {mMediaPlayer?.release()mMediaPlayer = null}
9. 其它常用方法

一般我们比较常用的就是获取当前播放进度、播放时长

  /*** 获取当前播放进度*/fun getPlayProgress(): Int {mMediaPlayer?.let {it.currentPosition}return 0}/*** 获取播放时长*/fun getPlayDuration(): Int {mMediaPlayer?.let {it.duration}return 0}
10.更新播放进度实现

 为了更好的体验我们可以通过定时器去定时更新播放进度,正常我们定时一秒去更新一次即可。

        mPlayProgress = PlayProgress(this@MusicMainActivity) private inner class PlayProgress(parent: MusicMainActivity?) : Runnable {private val weakReference: WeakReference<*>init {weakReference = WeakReference<Any?>(parent)}override fun run() {val parent = weakReference.get() as MusicMainActivity?parent?.let {parenttry {parent.mService?.let {parent.mProgress = it.playProgressif (parent.mProgress < 0) {parent.mProgress = 0}}parent.binding.musicSeekBar.progress = parent.mProgressparent.mHandler?.let {it.removeCallbacks(parent.mPlayProgress!!)it.postDelayed(parent.mPlayProgress!!, 1000)}} catch (e: Exception) {LogUtils.i(TAG, "PlayProgress e=${e.cause}")}}}}
11. 播放完成处理跟播放错误处理

播放完成我们可以根据设置的播放模式去执行对应的播放操作,播放错误正常我们是停止播放停止然后去播放下一首

    override fun onCompletion(mp: MediaPlayer?) {LogUtil.i(TAG, "onCompletion =$mMusicPosition")if (mPlayList.size <= 0) {Toast.makeText(mContext,"no music",Toast.LENGTH_SHORT).show()LogUtil.i(TAG, "onCompletion play list is null")return}when (mPlayMode) {LIST_ONCE -> {mMusicPosition++if (mPlayMode >= mPlayList.size) {mMusicPosition = mPlayList.size - 1pause()} else {play()}}LIST_CYCLE -> {mMusicPosition++mMusicPosition = if (mMusicPosition >= mPlayList.size) 0 else mMusicPositionplay()}SINGLE_CYCLE -> {mMusicPosition = if (mMusicPosition >= mPlayList.size) 0 else mMusicPositionplay()}LIST_RAND -> {mMusicPosition = getRandomMusic()play()}}}override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean {mMediaPlayer?.reset()stop()next()return true}

到这里我们就可以实现一个简单的音乐播放器了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/20565.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

HarmonyOS Next 关于页面渲染的性能优化方案

HarmonyOS Next 关于页面渲染的性能优化方案 HarmonyOS Next 应用开发中&#xff0c;用户的使用体验至关重要。其中用户启动APP到呈现页面主要包含三个步骤&#xff1a; 框架初始化页面加载布局渲染 从页面加载到布局渲染中&#xff0c;主要包含了6个环节&#xff1a; 执行页…

已解决centos7 yum报错:cannot find a valid baseurl for repo:base/7/x86_64的解决方案

出现cannot find a valid baseurl for repo:base/7/x86_64错误通常是由于YUM仓库源无法找到或无法访问&#xff0c;导致YUM无法正常工作。这种情况常见于CentOS 7系统。解决这个问题需要检查几个方面&#xff0c;如网络连接、DNS设置和YUM仓库源配置。 &#x1f9d1; 博主简介&…

架构图解析:如何构建高效的微服务系统

在当今的数字化浪潮中&#xff0c;构建高效、灵活且可扩展的系统已成为企业的重要目标。微服务架构作为一种先进的软件设计模式&#xff0c;通过将复杂的应用程序分解为一系列小型、独立的服务&#xff0c;显著提升了系统的灵活性、可扩展性和维护性。本文将通过解析微服务系统…

Label-studio-ml-backend 和YOLOV8 YOLO11自动化标注,目标检测,实例分割,图像分类,关键点估计,视频跟踪

这里写目录标题 1.目标检测 Detection2.实例分割 segment3.图像分类 classify4.关键点估计 Keypoint detection5.视频帧检测 video detect6.视频帧分类 video classify7.旋转目标检测 obb detect8.替换yolo11模型 给我点个赞吧&#xff0c;谢谢了附录coco80类名称 笔记本 华为m…

恒利联创携手Pearson VUE 亮相第62届高博会

2024年11月15日-17日&#xff0c;第62届中国高等教育博览会&#xff08;简称“高博会”&#xff09;在重庆举行&#xff0c;恒利联创携手全球领先的考试服务提供商Pearson Vue Certiport共同亮相&#xff0c;为中国院校展现并提供数字化职业技能的教育平台及学练考体系。 作为P…

linux复习2:简单命令简述

cp 复制单个文件 cp file.txt /path/to/destination/ 将 file.txt 复制到指定的目标目录。 复制多个文件 cp file1.txt file2.txt /path/to/destination/ 将 file1.txt 和 file2.txt 复制到指定的目标目录。 复制目录&#xff08;递归复制&#xff09; cp -r /path/to/source…

【逆向篇】抓取微信小程序源码 (附加逆向工具wxappUnpacker和使用方法)

抓取微信小程序源码附加逆向工具wxappUnpacker 文章目录前言一、工具准备1 解密工具2 逆向工具 二、解密小程序1.确认小程序包位置2.打开一个小程序3.解密小程序包 三、逆向小程序1、检查nodejs2、安装依赖3、正式逆向 该文章只是学习作用&#xff0c;如果侵权请联系删除&…

【C++】拷贝构造

一种特殊的构造函数&#xff0c;用自身这种类型来构造自身 Student stu1; Student stu2stu1;//调用拷贝构造如果类中没有自定义拷贝构造&#xff0c;类中会自动提供一个默认拷贝构造如果类中定义了自定义拷贝构造&#xff0c;类中不会提供默认拷贝构造 自定义拷贝构造 类名(…

C++的IO流

目录 1. C语言的输入与输出 2. 流是什么 3. CIO流 3.1 C标准IO流 3.2 C文件IO流 4 stringstream的简单介绍 1. 将数值类型数据格式化为字符串 2. 字符串拼接 3. 序列化和反序列化结构数据 1. C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。…

青训营刷题笔记11

水一个简单题&#xff1a; 问题描述 小C定义了一个“完美偶数”。一个正整数 xx 被认为是完美偶数需要满足以下两个条件&#xff1a; xx 是偶数&#xff1b;xx 的值在区间 [l,r][l,r] 之间。 现在&#xff0c;小C有一个长度为 nn 的数组 aa&#xff0c;她想知道在这个数组中…

游戏+AI的发展历程,AI技术在游戏行业的应用有哪些?

人工智能&#xff08;AI&#xff09;与游戏的结合&#xff0c;不仅是技术进步的体现&#xff0c;更是人类智慧的延伸。从最初的简单规则到如今的复杂决策系统&#xff0c;AI在游戏领域的发展历史可谓波澜壮阔。 早在2001年&#xff0c;就有研究指出游戏人工智能领域&#xff0…

Vue.js 插槽 Slots 实际应用 最近重构项目的时候遇到的...

前端开发中 插槽 Slots 是一个重要的概念 我们可以查看一下vue.js的官方文档 https://cn.vuejs.org/guide/components/slots 类似于连接通道一样 可以把核心代码逻辑搬到另外的地方 做一个引用 而原先的地方可能并不能这样书写 对于这个概念我在vue的官方文档里面找到了…

Windows11在WSL中安装QEMU-KVM

Windows11在WSL中安装QEMU-KVM 检查系统信息WSL检测安装所需软件端口转发 检查系统信息 打开设置-系统-系统信息&#xff08;拉到最下面&#xff09;&#xff0c;我的是 版本 Windows 11 专业版 版本号 24H2 安装日期 ‎2024/‎11/‎13 操作系统版本 26100.2314 体验 Windows …

【东莞石碣】戴尔R740服务器维修raid硬盘问题

1&#xff1a;石碣某塑料工厂下午报修一台戴尔R740服务器硬盘故障&#xff0c;催的还比较着急。 2&#xff1a;工程师经过跟用户确认故障的问题以及故障服务器型号和故障硬盘型号&#xff0c;产品和配件确认好后&#xff0c;公司仓库确认有该款硬盘现货&#xff0c;DELL 12T S…

SpringBoot学习笔记(一)

一、Spring Boot概述 &#xff08;一&#xff09;微服务概述 1、微服务 微服务&#xff08;英语&#xff1a;Microservices&#xff09;是一种软件架构风格&#xff0c;它是以专注于单一责任与功能的小型功能区块 (Small Building Blocks) 为基础&#xff0c;利用模块化的方式…

SD模型微调之LoRA

​ &#x1f33a;系列文章推荐&#x1f33a; 扩散模型系列文章正在持续的更新&#xff0c;更新节奏如下&#xff0c;先更新SD模型讲解&#xff0c;再更新相关的微调方法文章&#xff0c;敬请期待&#xff01;&#xff01;&#xff01;&#xff08;本文及其之前的文章均已更新&a…

手机远程控制电脑,让办公更快捷

在数字化办公的浪潮下&#xff0c;远程控制软件已成为连接工作与生活的桥梁。它使得用户能够通过一台设备&#xff08;主控端&#xff09;来操作另一台设备&#xff08;被控端&#xff09;&#xff0c;无论它们是否位于同一局域网内。这种软件广泛应用于远程办公、手机远程控制…

【Three.js基础学习】26. Animated galaxy

前言 shaders实现星系 课程回顾 使用顶点着色器为每个粒子设置动画 a属性 &#xff0c; u制服 &#xff0c;v变化 像素比&#xff1a;window.devicePixelRatio 自动从渲染器检索像素比 renderer.getPixelRatio() 如何尺寸衰减&#xff0c; 放大缩小视角时&#xff0c;粒子都是同…

基于Springboot + Vue的旧物置换网站管理系统(源码+lw+部署讲解+PPT)

前言 详细视频演示 论文参考 系统介绍 系统概述 核心功能 具体实现截图 1. 首页功能 2. 旧物信息功能 3. 网站公告功能 4. 用户管理功能&#xff08;管理员端&#xff09; 5. 置换交易管理功能 技术栈 后端框架SpringBoot 前端框架Vue 持久层框架MyBatis-Plus …

新书速览|循序渐进Spark大数据应用开发

《循序渐进Spark大数据应用开发》 本书内容 《循序渐进Spark大数据应用开发》结合作者一线开发实践&#xff0c;循序渐进地介绍了新版Apache Spark 3.x的开发技术。全书共10章&#xff0c;第1章和第2章主要介绍Spark的基本概念、安装&#xff0c;并演示如何编写最简单的Spark程…