iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 20
0
自我挑戰組

Kotlin and Android 30 days系列 第 20

Day 20 MediaPlayer/MediaRecorder (上)

  • 分享至 

  • xImage
  •  

今天學習使用 MediaPlayer 來播放 mp3 檔案
首先要建立 MediaPlayer 類別
這邊的想法是,建構類別時,把完成後 UI 要做的事情當作 CallBack 傳進來
然後在播放器的完成事件裡觸發它。
其它為相關的方法,後面會一一討論。

class CusMediaPlayer(ctx: Context, val callBack: () -> Unit) {

    var mediaPlayer: MediaPlayer = MediaPlayer.create(ctx, R.raw.cc)

    init {
        mediaPlayer.setOnCompletionListener {
            callBack.invoke()
        }
    }

    fun seekToProgress(progress: Int) {...}

    fun getDuration(): Int {...}

    fun getCurrentPosition(): Int {...}

    fun adjustVolume(value: Float) {...}

    fun playOrPauseMusic(): String {...}

    fun stopMusic(): String {...}
}

綁定音樂資源

首先我們要在 res 資料夾中先新增一個命名為 raw 的資料夾,並把要使用的 mp3 檔案放進去
接著就可以使用 MediaPlayer.create 方法建立 player

var mediaPlayer: MediaPlayer = MediaPlayer.create(ctx, R.raw.cc)

開始與暫停播放

由於播放和暫停鈕是同一個按鈕,我們希望在同一個方法處理它
可以使用 isPlaying 來判斷是否正在播放
最後順便把按鈕應該顯示的文字回傳回去

fun playOrPauseMusic(): String {
    if (mediaPlayer.isPlaying) {
        mediaPlayer.pause()
        return "Play"
    } else {
        mediaPlayer.start()
        return "Pause"
    }
}

停止音樂

停止音樂時,首先要把播放的進度使用 seekTo() 方法回歸到 0 (以毫秒計算)
接著呼叫 stop() 方法停止
由於 MediaPlayer 也有自己類似生命週期的定義,所以在 stop() 後會發現其他方法如 start()、pause()...等會失效,此時就要使用 prepare() 方法重新準備好它。

fun stopMusic(): String {
    mediaPlayer.seekTo(0)
    mediaPlayer.stop()
    mediaPlayer.prepare()
    return "Play"
}

調整音量

呼叫 setVolume() 方法來設定,有分左聲道和右聲道,100% 為 1f

fun adjustVolume(value: Float) {
    mediaPlayer.setVolume(value / 100f, value / 100f)
}

在 MainActivity 設定 SeekBar 的 setOnSeekBarChangeListener,會在拉動 SeekBar 時觸發。

 seekBarVolume.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                cusMediaPlayer.adjustVolume(progress.toFloat())
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {}

            override fun onStopTrackingTouch(seekBar: SeekBar?) {}

        })

設定音樂進度條

一樣是在 onProgressChanged 事件中去呼叫事件,實際是呼叫自訂類別裡的
seekTo() 方法來達成
這邊要注意到我們需要一個 flag 來判斷是不是正在做 "拉動" 這個動作,因為後面我們會使用 Runnable 來讓進度條自動跟著音樂的進度前進,如果沒有做這個判斷的話,這邊就會在沒拉動的時候也不斷觸發。

 seekBarProgress.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onStopTrackingTouch(seekBar: SeekBar?) {
                isSeeking = false
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {
                isSeeking = true
            }

            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                if (isSeeking) {
                    cusMediaPlayer.seekToProgress(progress)
                }
            }
        })
fun seekToProgress(progress: Int) {
    mediaPlayer.seekTo(progress)
}

讓進度條跟著音樂進度更新

首先在 MainActivity 中,先把進度條的總長度設定成跟音樂的總毫秒數一樣多

seekBarProgress.max = cusMediaPlayer.getDuration()
fun getDuration(): Int {
    return mediaPlayer.duration
}

接著寫一個更新進度條的方法,思路為在 runnable 中呼叫 runnable,達成類似 Timer 的效果
也就是每 500 毫秒更新一次進度條

private fun asyncProgressBar() {
    handler = Handler()
    runnable = Runnable {
        seekBarProgress.progress = cusMediaPlayer.getCurrentPosition()
        handler.postDelayed(runnable, 500)
    }
    runnable.run()
}
fun getCurrentPosition(): Int {
    return mediaPlayer.currentPosition
}

後續動畫和錄音部分會放在下篇討論。


上一篇
Day 19 SideMenu
下一篇
Day 21 MediaPlayer/MediaRecorder (下)
系列文
Kotlin and Android 30 days30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言