国产精品久久国产精麻豆99网站,激烈18禁高潮视频免费,老师含紧一点h边做边走视频动漫,双乳被一左一右的吸着

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

效果

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

音頻播放,是比較常見(jiàn)或常用的功能,比如音樂(lè)播放器、新聞播報(bào)、聽(tīng)書(shū)等等,而恰巧如果你想自定義一個(gè)音頻播放器的話,本文一定對(duì)你有幫助!

常用方法

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

Component Tree

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

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

初始化

/** * 初始化 及 資源準(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ò)請(qǐng)求的地址、uri等,看一下源碼:

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

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

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

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

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

/** * 播放器監(jiān)聽(tīng)事件 */ private fun initMediaPlayerListener() { mMediaPlayer?.setOnBufferingUpdateListener { mp, percent -> LogUtil.i("緩沖進(jìn)度$percent%") } mMediaPlayer?.setOnPreparedListener { LogUtil.i("準(zhǔn)備完成") //在準(zhǔn)備完成之后獲取信息,否則會(huì)有異常 val duration = mMediaPlayer?.duration//時(shí)長(zhǎng) val currentPosition = mMediaPlayer?.currentPosition//當(dāng)前位置 LogUtil.i("當(dāng)前位置$currentPosition/時(shí)長(zhǎng)$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("播放錯(cuò)誤") 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?) { //拖動(dòng)結(jié)束之后再設(shè)置,如果在onProgressChanged中設(shè)置會(huì)有雜音 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)聽(tīng)事件和按鈕操作事件。

https://blog.csdn.net/yechaoa

著重介紹兩個(gè):

1、setOnPreparedListener

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

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

并會(huì)回調(diào)OnErrorListener。

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

2、setOnSeekBarChangeListener

3個(gè)方法:

  • onProgressChanged 進(jìn)度改變
  • onStartTrackingTouch 開(kāi)始拖動(dòng)
  • onStopTrackingTouch 停止拖動(dòng)

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

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

所以建議用戶手動(dòng)拖動(dòng)來(lái)觸發(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() }

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

格式化播放時(shí)間

這個(gè)獲取時(shí)長(zhǎng)返回的是毫秒,所以我們還需要對(duì)其格式化操作。

/** * 格式化播放時(shí)間 */ 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" }

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

開(kāi)始播放

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

因?yàn)闆](méi)有播放中的回調(diào)接口,所以這里啟動(dòng)一個(gè)Timer獲取當(dāng)前位置并更新UI

Timer更新UI

/** * 每隔一秒執(zhí)行一次,更新當(dāng)前播放時(shí)間 */ 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() } } }

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

取消Timer

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

暫停/繼續(xù) 播放

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

如果只有一個(gè)事件觸發(fā)的話,可以這么來(lái)寫(xiě)。

重新播放

播放器并沒(méi)有自帶restart()方法,不過(guò)我們可以手動(dòng)把播放位置改到初始值,并調(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ù)源。

資源回收

及時(shí)的回收,有利于更好的性能。

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

ok,到此就講解完了。

寫(xiě)作不易,如果對(duì)你有用,點(diǎn)個(gè)贊吧 ^ – ^

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

国产成人亚洲精品无码影院bt| 欧美FREESEX黑人又粗又大 | 粗大的内捧猛烈进出爽大牛汉子文| 亚洲精品国产精品国自产观看 | 蜜桃AV无码国产丝袜在线观看| 精品黑人一区二区三区| 国产精品久久久久久影视| 亚洲国产精久久久久久久| 高h喷水荡肉爽腐男男并用小玩具| 性做久久久久久久| 久久精品国产亚洲av无码偷窥| 少妇饥渴偷公乱A级无码| 人妻少妇精品专区性色av | 国产精品18久久久久久麻辣| 曰本丰满熟妇XXXX性| 污污污www精品国产网站| 无码少妇精品一区二区免费动态| 国产精品久久久久乳精品爆| 亚洲一区二区三区女厕偷拍| 丝袜美腿一区二区三区| 高清毛片aaaaaaaaa片| 电梯里吸乳挺进我的身体视频| 欧美性猛交 xxxx 乱大交| 午夜福利在线观看午夜电影街bt| 精品亚洲欧美无人区乱码| 欧美又大又粗毛片多喷水| 无码人妻久久一区二区三区app| 暖暖爱视频免费| 我的漂亮女房东完整版在线韩剧 | 白袜校草被绑脱裤玩j| 天天躁日日躁狠狠躁| 亚洲乱码精品久久久久..| 校长把校花按在桌上看| 亚洲av无码乱码在线观看富二代| 亚洲av无码一区二区三区在线观看 | 狂猛欧美激情性xxxx大豆行情 | 小雪你的奶好大把腿张开| 精品久久人妻av中文字幕| 久久九九久精品国产免费直播 | 天天躁日日躁狠狠躁AV中文| 清冷医生h打开腿乖听话|