iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 21
0
Mobile Development

Android 音樂播放器自己來系列 第 21

播放介面實作(6) - Widget 頁面(顯示資訊)

今天來實作 Widget 顯示資訊的部分,因為 Widget 元件要透過 BroadcastReceiver 來接收事件,因此要透過 intent 發送。下面的 MediaControllerCallback 在實作播放功能時有介紹到,當播放資訊和狀態有改變時,會收到 callback,然後再將資訊送出。

private inner class MediaControllerCallback : MediaControllerCompat.Callback() {

        override fun onPlaybackStateChanged(state: PlaybackStateCompat?) {
            Log.d(TAG, "MediaControllerCallback onPlaybackStateChanged:$state")
            playbackState.postValue(state ?: EMPTY_PLAYBACK_STATE)
        }

        override fun onMetadataChanged(metadata: MediaMetadataCompat?) {
            Log.d(TAG, "MediaControllerCallback onMetadataChanged:$metadata")
            nowPlaying.postValue(
                if (metadata?.id == null) {
                    NOTHING_PLAYING
                } else {
                    sendWidgetIntent(metadata) // Add this to send ingo through intent 
                    metadata
                }
            )
        }
    }

將歌曲名稱、歌手名稱、專輯封面透過 intent,由 Broadcast 的方式送出。

private fun sendWidgetIntent(metadata: MediaMetadataCompat) {
        val intent = Intent(context, MusicAppWidget::class.java).apply {
            action = WidgetConstants.METADATA_CHANGED
            putExtra(WidgetConstants.ARGUMENT_SONG_ID, metadata.id)
            putExtra(WidgetConstants.ARGUMENT_TITLE, metadata.title)
            putExtra(WidgetConstants.ARGUMENT_SUBTITLE, metadata.displaySubtitle)
            putExtra(WidgetConstants.ARGUMENT_COVER_URI, metadata.displayIconUri.toString())
        }
        context.sendBroadcast(intent)
    }

在 MusicAppWidget 內,就可以透過 onReceive 收對應的 action,還有對應的 key,再將資訊取出,就類似 activity 傳資料到另外的 activity 的方式。

class MusicAppWidget : AppWidgetProvider() {

    ......

    override fun onReceive(context: Context, intent: Intent) {
        super.onReceive(context, intent)
        val appWidgetManager =
            context.getSystemService(Context.APPWIDGET_SERVICE) as AppWidgetManager
        val appWidgetIds =
            appWidgetManager.getAppWidgetIds(ComponentName(context, MusicAppWidget::class.java))

        when (intent.action) {
            WidgetConstants.METADATA_CHANGED -> {
                val id = intent.getLongExtra(WidgetConstants.ARGUMENT_SONG_ID, 0)
                val title = intent.getStringExtra(WidgetConstants.ARGUMENT_TITLE)!!
                val subtitle = intent.getStringExtra(WidgetConstants.ARGUMENT_SUBTITLE)!!
                val coverPath = intent.getStringExtra(WidgetConstants.ARGUMENT_COVER_URI)!!
                val metadata = WidgetMetadata(id, title, subtitle, coverPath)
                for (appWidgetId in appWidgetIds) {
                    metaChanged(context, metadata, appWidgetManager, appWidgetId)
                }
            }
        }
    }
}

可以看到這邊是透過 RemoteViews 的方式來更新,先選擇要更新的類型(字的內容、字體顏色、圖片內容),然後再填入對應的 View Id,再拿出相對應的內容填入。

private fun metaChanged(
        context: Context,
        widgetMetadata: WidgetMetadata,
        appWidgetManager: AppWidgetManager,
        appWidgetId: Int
    ) {
        val views = RemoteViews(context.packageName, R.layout.music_app_widget)
        views.setTextViewText(R.id.title, widgetMetadata.title)
        views.setTextViewText(R.id.subtitle, widgetMetadata.subtitle)

        //Use Glide to load cover

        appWidgetManager.updateAppWidget(appWidgetId, views)
    }

關於 Widget 的設定,主要是參考這個音樂 App 的寫法:canaree-music-player

ologe/canaree-music-player

成果圖:
https://i.imgur.com/YM9z9MX.gif

放大縮小:
https://i.imgur.com/QzfcJOZ.gif

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


上一篇
播放介面實作(6) - Widget 基礎
下一篇
播放介面實作(7) - Widget 頁面(控制)
系列文
Android 音樂播放器自己來30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言