iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 26
0

今天就來實作 setRepeatMode 和 setShuffleMode 吧,看 API 時還蠻直覺的,就塞個數字進去就好了 XD,但在 UI 操作時,使用者其實是切換狀態,舉例來說:shuffle 模式支援開啟和關閉,repeat 模式支援關閉、開啟、一首重複播放,就來看看要怎麼實作吧!

這兩個按鈕就加在 NowPlaying 頁面,在這天 NowPlaying 滿版 UI (資訊顯示) 所提到的畫面,在上下一首隔壁加入這兩個功能,關於圖的部分,也是用內建的向量圖,在選擇 icon 的地方,打上 shuffle 和 repeat,就會顯示相關的 icon 了,repeat 還會有兩張圖,這兩張圖都需要,分別對應到不同的 repeat mode。

關於 xml 的部分也是用 constraint layout 的方式加入,可以平均分配位置,這邊就不特別敘述了。在 NowPlayingFragment 內加入 ClickListener,點擊會切換模式,那切換模式後 icon 要有變化,這樣使用者才會知道是切換了,這邊等下再來講 XD

shuffleButton.setOnClickListener {
     nowPlayingViewModel.changeShuffleMode()
 }

repeatButton.setOnClickListener {
     nowPlayingViewModel.changeRepeatMode()
}

在 NowPlayingViewModel 加入對應的兩個 function,主要的概念也蠻直覺的,透過 mediaController 拿到目前的模式,然後設定下一個模式,再透過 transportControls 設定。

設定會用到的 Shuffle 模式 有這兩個,簡單來說是開和關 XD,還有另外兩個分別是:

  • SHUFFLE_MODE_GROUP: 歌單有分組時,可以對這個組別 shuffle
  • SHUFFLE_MODE_INVALID: Session 還沒初始化,還不支援 shuffle 的設定,這應該是從 mediaController 拿時會拿到,不會將這個數值塞入設定 XD

Repeat 模式就支援三種,除了開和關外,REPEAT_MODE_ONE 指的是對單一首歌 repeat,就是會一直重複播這首歌。另外兩種沒用到的同 Shuffle,也是 group 和 invalid。

private val shuffleModeChoices =
        listOf(PlaybackStateCompat.SHUFFLE_MODE_NONE, PlaybackStateCompat.SHUFFLE_MODE_ALL)
    private val repeatModeChoices =
        listOf(
            PlaybackStateCompat.REPEAT_MODE_NONE,
            PlaybackStateCompat.REPEAT_MODE_ONE,
            PlaybackStateCompat.REPEAT_MODE_ALL
        )
fun changeShuffleMode() {
        val nowShuffleMode =
            shuffleModeChoices.indexOf(musicServiceConnection.mediaController.shuffleMode)
        val targetShuffleMode = when (nowShuffleMode) {
            PlaybackStateCompat.SHUFFLE_MODE_NONE -> PlaybackStateCompat.SHUFFLE_MODE_ALL
            PlaybackStateCompat.SHUFFLE_MODE_ALL -> PlaybackStateCompat.SHUFFLE_MODE_NONE
            else -> PlaybackStateCompat.SHUFFLE_MODE_ALL
        }

        musicServiceConnection.transportControls.setShuffleMode(targetShuffleMode)
    }

fun changeRepeatMode() {
        val nowRepeatMode =
            repeatModeChoices.indexOf(musicServiceConnection.mediaController.repeatMode)
        val targetRepeatMode = when (nowRepeatMode) {
            PlaybackStateCompat.REPEAT_MODE_NONE -> PlaybackStateCompat.REPEAT_MODE_ONE
            PlaybackStateCompat.REPEAT_MODE_ONE -> PlaybackStateCompat.REPEAT_MODE_ALL
            PlaybackStateCompat.REPEAT_MODE_ALL -> PlaybackStateCompat.REPEAT_MODE_NONE
            else -> PlaybackStateCompat.REPEAT_MODE_ALL
        }

        musicServiceConnection.transportControls.setRepeatMode(targetRepeatMode)
    }

在 MusicServiceConnection 內有 MediaControllerCallback,在這個 callback 內再去 override 兩個 function,這樣就可以知道 shuffle mode 和 repeat mode 的變化了,當模式有改動時,這邊就會收到通知,然後 NowPlayingViewModel 會觀察 shuffleModeState,NowPlayingFragment 再觀察就可以知道目前的模式,顯示出對應的 icon。

private inner class MediaControllerCallback : MediaControllerCompat.Callback() {

    .....

    override fun onShuffleModeChanged(shuffleMode: Int) {
        super.onShuffleModeChanged(shuffleMode)
        Log.d(TAG, "MediaControllerCallback onShuffleModeChanged:$shuffleMode")
        shuffleModeState.postValue(shuffleMode)
    }

    override fun onRepeatModeChanged(repeatMode: Int) {
        super.onRepeatModeChanged(repeatMode)
        Log.d(TAG, "MediaControllerCallback onRepeatModeChanged:$repeatMode")
        repeatModeState.postValue(repeatMode)    
    }

}

在 NowPlayingFragment 內設定顯示的邏輯

nowPlayingViewModel.shuffleMode.observe(viewLifecycleOwner,
    Observer {
        when (it) {
            PlaybackStateCompat.SHUFFLE_MODE_NONE -> {
                shuffleButton.setColorFilter(Color.BLACK)
            }
            PlaybackStateCompat.SHUFFLE_MODE_ALL -> {
                shuffleButton.setColorFilter(ContextCompat.getColor(requireContext(),R.color.colorPrimary)
                )
            }
        }
    }
)

到這邊就大功告成了,可以注意到在 UI 頁面並不會管理狀態,UI 只負責切換指令和接收現在要顯示哪種模式,因為切換指令並不一定會從 UI 上觸發,Notification 或是 Widget 都是有可能的,不過這兩個地方還沒實作到 XD,如果要記錄上次的模式,這邊還需要實作 SharePreference 來記錄,就不會每次重開 App 都還要重新按。

成果圖:

  • Shuffle On

    https://i.imgur.com/ycjOFCG.gif

  • Repeat All

    https://i.imgur.com/WTDqqbv.gif

  • Repeat One

    https://i.imgur.com/rrHFSzo.gif

程式碼在這,分支名稱(day26_shuffle_repeat_mode): Fancy/day26_shuffle_repeat_mode


上一篇
播放模式功能(1) - 介紹
下一篇
播放器測試(1)
系列文
Android 音樂播放器自己來30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言