亚洲熟妇av一区二区三区,久久久久久精品观看sss,免费观看四虎精品国产永久,国产成人精品一区二三区熟女,天堂网在线最新版www资源网

Android MediaPlayer音頻播放器詳解(android mediaplayer播放音樂)

效果

Android MediaPlayer音頻播放器詳解(android mediaplayer播放音樂)

音頻播放,是比較常見或常用的功能,比如音樂播放器、新聞播報、聽書等等,而恰巧如果你想自定義一個音頻播放器的話,本文一定對你有幫助!

常用方法

  • start() 開始播放
  • pause() 暫停播放
  • stop() 停止播放
  • prepare() 資源準(zhǔn)備
  • prepareAsync() 異步準(zhǔn)備,不阻塞UI線程
  • seekTo(int msec) 定位到指定位置,單位毫秒
  • isLooping 是否循環(huán)播放
  • isPlaying 播放狀態(tài)
  • duration 總時長
  • currentPosition 當(dāng)前位置
  • release() 資源釋放

Component Tree

具體的xml代碼就不貼了,看一下組件樹

Android MediaPlayer音頻播放器詳解(android mediaplayer播放音樂)

初始化

/** * 初始化 及 資源準(zhǔn)備 */ private fun audioPrepare(path: String) { mMediaPlayer = MediaPlayer().apply { setDataSource(path)//支持文件、網(wǎng)絡(luò)地址、uri prepareAsync()//異步準(zhǔn)備,不阻塞UI線程 isLooping = false//循環(huán)播放 } initMediaPlayerListener() }

setDataSource,設(shè)置數(shù)據(jù)源,支持本地文件、網(wǎng)絡(luò)請求的地址、uri等,看一下源碼:

  • setDataSource(FileDescriptor)
  • setDataSource(String)
  • setDataSource(Context, Uri)
  • setDataSource(FileDescriptor, long, long)
  • setDataSource(MediaDataSource)

如果是本地文件,注意讀寫權(quán)限。

prepareAsync() 異步準(zhǔn)備,不阻塞UI線程

然后看一下調(diào)用的initMediaPlayerListener 方法

播放器監(jiān)聽事件及交互

/** * 播放器監(jiān)聽事件 */ private fun initMediaPlayerListener() { mMediaPlayer?.setOnBufferingUpdateListener { mp, percent -> LogUtil.i("緩沖進度$percent%") } mMediaPlayer?.setOnPreparedListener { LogUtil.i("準(zhǔn)備完成") //在準(zhǔn)備完成之后獲取信息,否則會有異常 val duration = mMediaPlayer?.duration//時長 val currentPosition = mMediaPlayer?.currentPosition//當(dāng)前位置 LogUtil.i("當(dāng)前位置$currentPosition/時長$duration") tv_currentPosition.text = formatDuration(currentPosition!!) tv_duration.text = formatDuration(duration!!) seek_bar.max = duration } mMediaPlayer?.setOnCompletionListener { LogUtil.i("播放完畢") } mMediaPlayer?.setOnErrorListener { mp, what, extra -> LogUtil.i("播放錯誤") return@setOnErrorListener true } mMediaPlayer?.setOnSeekCompleteListener { LogUtil.i("定位完成") } seek_bar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { tv_currentPosition.text = formatDuration(seekBar!!.progress) } override fun onStartTrackingTouch(seekBar: SeekBar?) { } override fun onStopTrackingTouch(seekBar: SeekBar?) { //拖動結(jié)束之后再設(shè)置,如果在onProgressChanged中設(shè)置會有雜音 mMediaPlayer?.seekTo(seekBar!!.progress) tv_currentPosition.text = formatDuration(seekBar!!.progress) } }) btn_start.setOnClickListener { audioStart() } btn_pause.setOnClickListener { audioPause() } btn_seek.setOnClickListener { seek_bar.progress = (seek_bar.max * 0.8).roundToInt() mMediaPlayer?.seekTo(seek_bar!!.progress) tv_currentPosition.text = formatDuration(seek_bar!!.progress) audioStart() } btn_restart.setOnClickListener { audioRestart() } }

主要 是一些播放器的監(jiān)聽事件和按鈕操作事件。

https://blog.csdn.net/yechaoa

著重介紹兩個:

1、setOnPreparedListener

注意,在獲取資源時長的時候,需要在播放器準(zhǔn)備完成之后獲取,否則會有異常:

Attempt to call getDuration in wrong state: mPlayer=0x7244676280, mCurrentState=4error (-38, 0)

并會回調(diào)OnErrorListener。

然后設(shè)置顯示,并把時長賦值給seek_bar的最大值。

2、setOnSeekBarChangeListener

3個方法:

  • onProgressChanged 進度改變
  • onStartTrackingTouch 開始拖動
  • onStopTrackingTouch 停止拖動

我們需要在改變中和改變后對當(dāng)前播放時長進行更新,并在最后的位置進行播放操作。

如果程序上沒有定位到指定播放位置這種操作的話,不要在onProgressChanged 中執(zhí)行播放操作,因為頻繁的進度改變,頻繁的調(diào)用播放,會有雜音。

所以建議用戶手動拖動來觸發(fā)播放。

如果非要程序可以跳到指定位置播放的話,建議如下操作:

btn_seek.setOnClickListener { seek_bar.progress = (seek_bar.max * 0.8).roundToInt() mMediaPlayer?.seekTo(seek_bar!!.progress) tv_currentPosition.text = formatDuration(seek_bar!!.progress) audioStart() }

手動賦值progress ,并調(diào)用播放。

格式化播放時間

這個獲取時長返回的是毫秒,所以我們還需要對其格式化操作。

/** * 格式化播放時間 */ private fun formatDuration(duration: Int): String { val d = duration / 1000 val minute = d / 60 val second = d % 60 val m: String = if (minute < 10) "0$minute" else "$minute" val s: String = if (second < 10) "0$second" else "$second" return "$m:$s" }

做了一個判斷,不足兩位數(shù)則前位補0。

開始播放

/** * 開始播放 */ private fun audioStart() { mMediaPlayer?.run { if (!this.isPlaying) { start() startTimer() } } }

因為沒有播放中的回調(diào)接口,所以這里啟動一個Timer獲取當(dāng)前位置并更新UI

Timer更新UI

/** * 每隔一秒執(zhí)行一次,更新當(dāng)前播放時間 */ private fun startTimer() { mTimer = Timer().apply { schedule(object : TimerTask() { override fun run() { //非ui線程不能更新view,所以這里賦值給seek_bar,在seek_bar的事件中去更新 seek_bar.progress = mMediaPlayer!!.currentPosition //tv_currentPosition.text = formatDuration(mMediaPlayer!!.currentPosition) } }, 0, 1000) } }

這里要注意,非ui線程不能更新view,所以這里賦值給seek_bar,在seek_bar的onProgressChanged 回調(diào)中去更新。

暫停播放

/** * 暫停播放 */ private fun audioPause() { mMediaPlayer?.run { if (this.isPlaying) { pause() cancelTimer() } } }

同樣,暫停的時候取消Timer,做到資源及時回收。

取消Timer

private fun cancelTimer() { mTimer?.run { cancel() mTimer = null } }

暫停/繼續(xù) 播放

/** * 暫停/繼續(xù) 播放 */ private fun audioToggle() { mMediaPlayer?.run { if (this.isPlaying) { audioPause() } else { audioStart() } } }

如果只有一個事件觸發(fā)的話,可以這么來寫。

重新播放

播放器并沒有自帶restart()方法,不過我們可以手動把播放位置改到初始值,并調(diào)用播放。

/** * 重新播放 */ private fun audioRestart() { mMediaPlayer?.run { //定位到指定位置,單位毫秒 seekTo(0) audioStart() seek_bar.progress = 0 tv_currentPosition.text = formatDuration(seek_bar!!.progress) //如果是下一首,可以調(diào)用reset()重置,然后set新的數(shù)據(jù)源 } }

如果是下一首,可以調(diào)用reset()重置,然后set新的數(shù)據(jù)源。

資源回收

及時的回收,有利于更好的性能。

override fun onDestroy() { mAgentWeb.webLifeCycle.onDestroy() super.onDestroy() cancelTimer() mMediaPlayer?.run { stop() release() mMediaPlayer = null } }

ok,到此就講解完了。

寫作不易,如果對你有用,點個贊吧 ^ – ^

版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請發(fā)送郵件至 舉報,一經(jīng)查實,本站將立刻刪除。