透過「資訊一覽」建立小工具

1. 事前準備

本程式碼實驗室會逐步引導您為 SociaLite 建立應用程式小工具。首先,您將建構簡易的「資訊一覽」小工具,並將其加入 SociaLite 及主畫面。接著,您將使用「資訊一覽」元件和主題為小工具加入零狀態。然後,本程式碼實驗室會逐步引導您支援使用者互動,讓使用者能從小工具中選取常用聯絡人。最後,您將學習如何從應用程式更新小工具。

必備條件

  • 具備 Kotlin 基本知識。
  • 完成「設定 Android Studio」程式碼實驗室,或熟悉 Android Studio 使用方式,且能在 Android 15 模擬器或搭載 Android 15 的實體裝置上測試應用程式。
  • 具備 Hilt 基本知識。
  • 具備 Compose 基本知識。雖然「資訊一覽」並不使用 Jetpack Compose 的可組合函式,但會重複使用框架和程式設計樣式。

本程式碼研究室涵蓋內容

  • 如何設定應用程式以支援小工具。
  • 如何使用「資訊一覽」元件建構回應式版面配置。
  • 如何使用 GlanceTheme 在使用者的主畫面支援動態顏色。
  • 如何在小工具中處理使用者互動。
  • 如何從應用程式更新小工具。

需求條件

  • 最新版 Android Studio。
  • 搭載 Android 12 以上版本的測試裝置或模擬器。
  • Android 12 以上版本的 SDK。

顯示 SociaLite 小工具的 Android 主畫面

2. 做好準備

取得範例程式碼

  1. 如果您已完成「因應 Android 15 強制採用的無邊框措施」或「新增預測返回動畫」程式碼實驗室,則您已擁有範例程式碼,請跳到「新增小工具」部分。
  2. 前往 GitHub 下載範例程式碼

或者,您也可以複製存放區,並查看 codelab_improve_android_experience_2024 分支。

 git clone git@github.com:android/socialite.git
 cd socialite
 git checkout codelab_improve_android_experience_2024
  1. 在 Android Studio 中開啟 SociaLite,然後在 Android 15 裝置或模擬器上執行該應用程式。您會看到像是下方圖片的畫面:

fb043d54dd01b3e5.png

採用手勢操作模式的 SociaLite

3. 新增小工具

什麼是小工具?

小工具是應用程式的一部分,可嵌入其他 Android 應用程式。最常見的小工具就是使用者的主畫面。

為應用程式加入小工具,可以讓使用者快速啟動常見任務、一眼掌握豐富資訊,以及使用您的內容自訂裝置。

什麼是「資訊一覽」?

Jetpack「資訊一覽」是一個使用 Kotlin 編寫小工具的程式庫,所用的 API 類似 Compose。「資訊一覽」與 Compose 具備幾個相同優點,例如可重新組合,能用 Kotlin 以宣告方式編寫 UI 程式碼,以及具有結構明確的元件。「資訊一覽」也減少了編寫小工具時使用 XML 遠端檢視的需求。

建立小工具

Android 上的小工具會在 AndroidManifest 中宣告為 <receiver> 元素。這個接收器應匯出,處理 android.appwidget.action.APPWIDGET_UPDATE 動作意圖,並透過 android.appwidget.provider 中繼資料元素提供應用程式小工具設定檔。

將小工具加入 SociaLite

顯示 SociaLite 小工具的 Android 主畫面

您想在 SociaLite 中加入小工具,讓使用者看到自己的常用聯絡人,以及是否有他們的未讀訊息。如有未讀訊息,使用者輕觸小工具後,系統應開啟與相應常用聯絡人的即時通訊。此外,您會使用「資訊一覽」元件和主題設定,透過回應式設計與動態顏色,確保小工具呈現最佳效果。

首先,您要將靜態的「Hello World」小工具加入 SociaLite。之後,您可以擴充小工具的功能。

為達成這個目標,您需要執行以下操作:

  1. 將「資訊一覽」的依附元件加入應用程式。
  2. 建立 GlanceAppWidget 實作項目。
  3. 建立 GlanceAppWidgetReceiver
  4. 使用應用程式小工具資訊 XML 檔案來設定小工具。
  5. 將接收器和應用程式小工具資訊加入 AndroidManifest.xml 檔案。

將「資訊一覽」加入專案

範例程式碼已將「資訊一覽」的版本和程式庫座標加入 SociaLite 的版本目錄:libs.versions.toml

libs.versions.toml

[versions]
//..

glance = "1.1.0-beta02"

[libraries]
glance-appwidget = { group = "androidx.glance", name = "glance-appwidget", version.ref = "glance" }
glance-material = { group = "androidx.glance", name = "glance-material3", version.ref = "glance" }

此外,「資訊一覽」的依附元件也已包含在 SociaLite 的 app/build.gradle.kts 檔案中。

build.gradle.kts
dependencies {
...
implementation(libs.glance.appwidget)
implementation(libs.glance.material)

...
}
  • 如您已修改這些檔案,請同步專案以下載「資訊一覽」程式庫。

建立 GlanceAppWidgetGlanceAppWidgetReceiver

Android 會透過廣播接收器來通知 SociaLite 某個小工具已新增、需要更新或已移除。「資訊一覽」提供一個抽象的接收器類別 GlanceAppWidgetReceiver,該類別可擴充 AppWidgetProvider。

GlanceAppWidgetReceiver 實作項目也負責提供 GlanceAppWidget 的例項。這個類別會將「資訊一覽」的可組合函式算繪成遠端檢視。

範例程式碼包含兩個類別:SocialiteAppWidget (用以擴充 GlanceAppWidget) 及 SocialiteAppWidgetReceiver (用以擴充 GlanceAppWidgetReceiver)。

如要開始,請按照下列步驟操作:

  1. 前往 app/src/main/java/com/google/android/samples/socialite/ 找到 widget 套件。
  2. 開啟 SociaLiteAppWidget 類別。此類別會覆寫 provideGlance 方法。
  3. 使用呼叫 provideContent 取代 TODO,然後以參數形式傳遞小工具的可組合函式。目前這個小工具僅會顯示 Hello World 訊息,但您會在本程式碼實驗室的後續部分中學習如何加入更多功能。
package com.google.android.samples.socialite.widget

import android.content.Context
import androidx.glance.GlanceId
import androidx.glance.GlanceTheme
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.provideContent
import androidx.glance.text.Text

class SociaLiteAppWidget : GlanceAppWidget() {
   override suspend fun provideGlance(context: Context, id: GlanceId) {
       provideContent {
           GlanceTheme {
               Text("Hello World")
           }
       }
   }
}
  1. 接著,開啟 widget 套件中的 SociaLiteAppWidgetReceiver 類別。您的接收器目前會提供一個 SociaLiteWidget 的例項,但您會在接下來的章節中學習如何加入更多功能。
  2. 使用 SociaLiteAppWidget() 建構函式取代 TODO
package com.google.android.samples.socialite.widget

import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver

class SociaLiteAppWidgetReceiver : GlanceAppWidgetReceiver() {
   override val glanceAppWidget: GlanceAppWidget = SociaLiteAppWidget()
}

現在您已準備好設定 Android 來顯示您的小工具,並允許使用者將其新增至主畫面。

新增應用程式小工具供應商資訊

  1. 在 res/xml 上按一下滑鼠右鍵,然後依序點選「New」(新增) >「XML resource file」(XML 資源檔案)
  2. 輸入 socialite_widget_info 做為檔案名稱,appwidget-provider 做為根元素,然後按一下「OK」(確定)。這個檔案包含 AppWidgetHost 用來初始顯示小工具的 appwidget 所需的中繼資料。
  3. 在 socialite_widget_info.xml 檔案中加入以下程式碼:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
   android:resizeMode="horizontal|vertical"
   android:updatePeriodMillis="3600000"
   android:minHeight="128dp"
   android:minWidth="128dp"

   android:minResizeHeight="128dp"
   android:minResizeWidth="128dp"
   android:configure="com.google.android.samples.socialite.widget.SociaLiteAppWidgetConfigActivity"
   android:widgetFeatures="configuration_optional|reconfigurable"
   android:previewImage="@drawable/widget_preview"
   android:maxResizeHeight="512dp"
   android:maxResizeWidth="512dp"
   android:targetCellWidth="2"
   android:targetCellHeight="2"
   android:initialLayout="@layout/glance_default_loading_layout">
</appwidget-provider>

下表概略說明此程式碼中的每個屬性:

屬性名稱

說明

resizeMode

系統可能會調整小工具的垂直和水平大小。

targetCellWidth, targetCellHeight

指定小工具加入主畫面時的預設大小。

updatePeriodMillis

控制小工具主機何時會重新整理小工具。只要您的應用程式正在執行且有新資訊可供顯示,就可以更新小工具。

minResizeHeight,minResizeWidth

設定小工具可調整的最小尺寸。

minHeight,minWidth

指定小工具加至主畫面時的最小預設尺寸。

initialLayout

在「資訊一覽」算繪可組合函式時,顯示初始版面配置。

previewImage

提供會顯示在小工具挑選器中的小工具靜態圖像。

widgetFeatures

指示小工具支援的各種功能。這些內容是給小工具主機的提示,實際上並不會改變小工具的行為。

在本程式碼實驗室中,您的旗標告訴主機,小工具加入主畫面之前無需設定,但在加入後可以設定。

configure

設定活動類別的名稱。這個活動可在稍後設定小工具。

如要查看所有可用的屬性,包括 API 31 以上版本的功能,請參閱 AppWidgetProviderInfo

更新 AndroidManifest 並測試

最後,您已準備好更新 AndroidManifest.xml 檔案並測試小工具。請在檔案中將 receiver 元素定義為 application 元素的子項。這個接收器會處理 APPWIDGET_UPDATE 意圖,並將 appwidget 中繼資料提供給 Android 啟動器。

如要開始,請按照下列步驟操作:

  1. SociaLiteAppWidgetReceiver 建立 receiver 元素,以供匯出。複製下列程式碼並貼到 AndroidManifest.xml 檔案中 application 元素之後:
<receiver
   android:name=".widget.SociaLiteAppWidgetReceiver"
   android:exported="true"
   android:label="Favorite Contact">

   <intent-filter>
       <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
   </intent-filter>

   <meta-data
       android:name="android.appwidget.provider"
       android:resource="@xml/socialite_widget_info" />
</receiver>
  1. 編譯並執行應用程式。
  2. 應用程式執行後,將小工具新增到主畫面。例如,在 Pixel 上,長按背景,選取「Widgets」(小工具) >「SociaLite」。您應該可以將小工具新增到主畫面。

Android 主畫面顯示開發中的小工具小工具是透明的,並顯示訊息

背景透明的小工具顯示「Hello World」。不可否認,這個小工具目前外觀簡陋,功能也有限。在下一節中,您會為小工具加入更複雜的版面配置,並使用 Material Design 的繽紛色彩美化外觀。

4. 改善設計

目前的小工具僅具靜態功能,缺乏實用小工具應具備的許多特徵。一個實用的小工具應該:

  • 展示簡潔的最新內容,並提供簡單易用的功能。
  • 能夠調整版面配置,盡量減少突兀的空隙。
  • 套用應用程式小工具主機背景的顏色。

如要深入瞭解何謂實用的小工具,請參閱小工具

新增 Scaffold

現在您要更新小工具,以顯示在「資訊一覽」Scaffold 元件中。

Scaffold 由「資訊一覽」程式庫提供,這個簡單的 Slot API 可顯示具有 TitleBar 的小工具使用者介面。這個介面會將背景顏色設定為 GlanceTheme.colors.widgetBackground,並套用邊框間距,是設計小工具時的頂層元件。

如要開始,請按照下列步驟操作:

  1. 使用下列程式碼取代 SociaLiteAppWidget 的實作項目:
package com.google.android.samples.socialite.widget

import android.content.Context
import androidx.compose.runtime.Composable
import androidx.glance.GlanceId
import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme
import androidx.glance.ImageProvider
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.components.Scaffold
import androidx.glance.appwidget.components.TitleBar
import androidx.glance.appwidget.provideContent
import androidx.glance.layout.fillMaxSize
import androidx.glance.text.Text
import com.google.android.samples.socialite.R

class SociaLiteAppWidget : GlanceAppWidget() {
   override suspend fun provideGlance(context: Context, id: GlanceId) {
       provideContent {
           GlanceTheme() {
               Content()
           }
       }
   }

   @Composable
   private fun Content() {
       Scaffold(titleBar = {TitleBar(startIcon = ImageProvider(R.drawable.ic_launcher_monochrome), title = "SociaLite")},
           modifier = GlanceModifier.fillMaxSize()) {
           Text("Hello World")
       }
   }
}
  1. 如要查看更新,請重新執行應用程式,然後將小工具的新副本新增到主畫面。

Android 主畫面顯示開發中的小工具小工具擁有不透明的背景和標題

請記住,小工具是由外部主機顯示的遠端檢視。稍後,您會學習如何新增功能,以在應用程式內部自動更新小工具。在那之前,您必須從小工具挑選器新增小工具,才能看到程式碼的變更。

如您所見,小工具的呈現效果已比之前要好,但與其他小工具相比,顏色似乎不太合適。在主畫面中,小工具的顏色應該配合使用者的主題設定。使用動態顏色符記,您就可以讓小工具的主題配合裝置的桌布和主題。

加入動態顏色

現在,請將 widgetBackground 顏色符記加入到 Scaffold 背景,並將 onSurface 顏色符記加入 TitleBar 文字及 Text 元件。如要更新文字樣式,請匯入 TextStyle「資訊一覽」類別。如要更新 Scaffold 背景,請將 ScaffoldbackgroundColor 屬性設定為 GlanceTheme.colors.widgetBackground

如要開始,請按照下列步驟操作:

  1. SociaLiteAppWidget.kt 檔案中引入新的匯入內容。
//Add to the imports section of your Kotlin code.
import androidx.glance.text.TextStyle
  1. 更新 Content 可組合函式以新增 widgetBackground
Scaffold(
   titleBar = {
       TitleBar(
           textColor = GlanceTheme.colors.onSurface,
           startIcon = ImageProvider(R.drawable.ic_launcher_monochrome),
           title = "SociaLite",
       )
   },
   backgroundColor = GlanceTheme.colors.widgetBackground,
   modifier = GlanceModifier.fillMaxSize(),
) {
   Text(text = "Hello World", style = TextStyle(color = GlanceTheme.colors.onSurface))
}
  1. 如要查看更新,請重新執行應用程式,並將小工具的新副本新增到主畫面。

現在,小工具與主畫面上其他小工具的主題會保持一致;若您變更背景或設定深色模式,小工具會自動更新顏色。若使用五彩繽紛的背景,小工具會根據所處區域的顏色自動調整外觀。

Android 主畫面顯示淺色主題下的「Hello World」小工具淺色主題的主畫面

顯示深色主題下的「Hello World」小工具的 Android 主畫面深色主題的主畫面

新增零狀態

現在您需要考慮狀態和小工具的設定。小工具新增到主畫面後,但尚未完成設定時,通常最好顯示零狀態。這種狀態可提示使用者設定小工具。您需要為小工具加入設定活動,並從零狀態連結至該活動。

本程式碼實驗室提供用來儲存、存取和修改小工具設定狀態的類別。您將學習如何新增程式碼以更新小工具 UI 來顯示此狀態,並建立 lambda 動作來處理使用者的輕觸動作。

檢查小工具模型

請花點時間查看 com.google.android.samples.socialite.widget.model 套件中的類別。

其中包含 WidgetModelWidgetModelDaoWidgetModelRepository 類別。這些類別已包含在本程式碼實驗室的範例程式碼中,並處理將小工具狀態保存到底層 Room 資料庫的問題。此外,這些類別使用 Hilt 來管理生命週期。

WidgetModel 類別包含一個由 Android 指派的 widgetId、所顯示的 SociaLite 聯絡人的 contactId、要顯示的 displayNamephoto,以及一個布林值 (表示是否有來自聯絡人的未讀訊息)。SociaLiteAppWidget 可組合函式會取用這些內容,並顯示在小工具中。

WidgetModelDao資料存取物件,可簡化對 SociaLite 資料庫的存取權。WidgetModelRepository 則提供建立、讀取、更新及刪除 WidgetModel 例項的便利函式。這些類別由 Hilt 建立,並透過依附元件插入功能插入應用程式。

  • 前往 app/src/main/java/com/google/android/samples/socialite/widget/model/,開啟 model 套件中的 WidgetModel.kt 檔案。

這是一個使用 Entity 註解的 data 類別。Android 會為每個小工具例項指派一個專屬的 ID,而 SociaLite 會將這個 ID 用做模型資料的主鍵。模型的每個例項都會追蹤關聯聯絡人的基本資訊,以及是否有來自聯絡人的未讀訊息。

@Entity(
    foreignKeys = [
        ForeignKey(
            entity = Contact::class,
            parentColumns = ["id"],
            childColumns = ["contactId"],
            onDelete = ForeignKey.CASCADE,
        ),
    ],
    indices = [
        Index("widgetId"),
        Index("contactId"),
    ],
)
data class WidgetModel(
    @PrimaryKey val widgetId: Int,
    val contactId: Long,
    val displayName: String,
    val photo: String,
    val unreadMessages: Boolean = false,
) : WidgetState

零狀態

您想讓 Content 可組合函式從 WidgetModelRepository 載入小工具的模型。若沒有可用的模型,就顯示零狀態;否則顯示小工具的一般內容。目前,一般內容為「Hello World」訊息,但在下一章節,您會建立更出色的介面。

您將使用 when 運算式取代 Content 可組合函式,根據是否有可用模型,顯示 ZeroState 可組合函式或 Text 預留位置。

  1. provideGlance 方法中,於可組合函式之外,取得 WidgetModelRepository 和目前小工具 ID 的參照。在 SociaLiteAppWidget provideGlance 方法的 provideContent 之前新增以下行。
override suspend fun provideGlance(context: Context, id: GlanceId) {
   val widgetId = GlanceAppWidgetManager(context).getAppWidgetId(id)
   val repository = WidgetModelRepository.get(context)

您也可能需要新增以下匯入項目:

import com.google.android.samples.socialite.widget.model.WidgetModel
import com.google.android.samples.socialite.widget.model.WidgetModelRepository
import com.google.android.samples.socialite.widget.model.WidgetState.Loading
import androidx.glance.appwidget.GlanceAppWidgetManager
  1. 將存放區和小工具 ID 以參數形式加入 Content 可組合函式,然後用以載入模型。更新 Content 可組合函式的簽章,並新增以下行:
private fun Content(repository: WidgetModelRepository, widgetId: Int) {
   val model = repository.loadModel(widgetId).collectAsState(Loading).value
  1. 若 Android Studio 沒有自動新增以下匯入項目,請手動新增。
import androidx.compose.runtime.collectAsState

此外,您也需要更新 provideGlance,將小工具 ID 和存放區傳遞給 Content

請使用以下內容取代 provideGlance

override suspend fun provideGlance(context: Context, id: GlanceId) {
        val widgetId = GlanceAppWidgetManager(context).getAppWidgetId(id)
        val repository = WidgetModelRepository.get(context)

        provideContent {
            GlanceTheme {
                Content(repository, widgetId)
            }
        }
    }
  1. Content 可組合函式中,根據模型是否存在來決定要顯示的狀態。使用這個 when 區塊取代 Scaffold 元件及其內容,將 Scaffold 與小工具內容移到 ZeroState 可組合函式中:
   when (model) {
       is WidgetModel -> {Text("Hello World")}
       else -> ZeroState(widgetId)
   }

ZeroState 可組合函式已包含在 com.google.android.samples.socialite.widget.ui 套件內的範例程式碼中。

  1. 若 Android Studio 沒有自動匯入 com.google.android.samples.socialite.widget.ui 套件,請在 SociaLiteAppWidget 的匯入部分新增下列程式碼。
import com.google.android.samples.socialite.widget.ui.ZeroState
  1. 如要查看更新,請重新執行應用程式,並將小工具的新副本新增到主畫面。您會看到小工具顯示 ZeroState 元件和一個按鈕。按一下按鈕會開啟設定活動。在下一節中,您將透過這個活動更新小工具的狀態。

Android 主畫面顯示 SociaLite 小工具處於零狀態。零狀態下顯示單一按鈕。

SociaLite AppWidget 設定活動顯示 4 個可供挑選的聯絡人。

設定活動

檢視 ZeroState 可組合函式。這個函式可在 ZeroState.kt 檔案的 com.google.android.samples.socialite.widget.ui 套件中找到。

@Composable
fun ZeroState(widgetId: Int) {
   val widgetIdKey = ActionParameters.Key<Int>(AppWidgetManager.EXTRA_APPWIDGET_ID)
Scaffold(
   titleBar = {
       TitleBar(
           modifier = GlanceModifier.clickable(actionStartActivity(MainActivity::class.java)),
           textColor = GlanceTheme.colors.onSurface,
           startIcon = ImageProvider(R.drawable.ic_launcher_monochrome),
           title = "SociaLite",
       )
   },
   backgroundColor = GlanceTheme.colors.widgetBackground,
   modifier = GlanceModifier.fillMaxSize(),
) {
   Box(modifier = GlanceModifier.fillMaxSize(), contentAlignment = Alignment.Center) {
       Button(
           text = "Select Favorite Contact",
           onClick = actionStartActivity<SociaLiteAppWidgetConfigActivity>(
               parameters = actionParametersOf(widgetIdKey to widgetId),
           ),
       )
   }
}

}

Scaffold 可組合函式已移入 ZeroState 可組合函式。TitleBar 具有 clickable 修飾符,可開啟 SociaLite 的主要活動。ZeroState 使用「資訊一覽」Button 可組合函式向使用者顯示行動號召,按一下後會開啟 SociaLiteAppWidgetConfigActivity 活動,並以意圖額外項目形式加入小工具 ID。這兩個動作都使用「資訊一覽」的 actionStartActivity 便利函式。如要進一步瞭解動作,請參閱處理使用者互動

  1. 檢視 SociaLiteAppWidgetConfigActivity 如何用來更新小工具的設定。這個類別也是小工具的設定活動。設定活動會讀取具有 AppWidgetManager.*EXTRA_APPWIDGET_ID.* 索引鍵的整數意圖額外項目。如要進一步瞭解設定活動,請參閱協助使用者設定應用程式小工具
  2. SociaLiteAppWidgetConfigActivity 中,請使用以下程式碼取代 ContactRow onClick 屬性中的 TODO
{
  coroutineScope.launch {

     widgetModelRepository.createOrUpdate(
       WidgetModel(
           appWidgetId,
           contact.id,
           contact.name,
           contact.iconUri.toString(),
           false,
       ),
     )
     SociaLiteAppWidget().updateAll(this@SociaLiteAppWidgetConfigActivity)
     val resultValue = Intent().putExtra(
       AppWidgetManager.EXTRA_APPWIDGET_ID,
       appWidgetId,
     )
     setResult(RESULT_OK, resultValue)
     finish()
  }
}

若 Android Studio 沒有自動新增以下包含內容,請新增相關內容:

import com.google.android.samples.socialite.widget.model.WidgetModel
import androidx.glance.appwidget.updateAll
import kotlinx.coroutines.launch

這個程式碼區塊會更新您的小工具狀態。首先,這個區塊會使用存放區來儲存或更新 WidgetModel 中所選聯絡人的資訊。接著,它會呼叫 updateAll 暫停函式。這個函式會更新主畫面上的所有小工具,您可以在應用程式的任何地方呼叫這個函式。最後,這個區塊會設定活動結果,指示已成功更新小工具。

  1. 執行並取代主畫面上的小工具。您應該會看到新的零狀態。

Android 主畫面顯示 SociaLite 小工具處於零狀態。零狀態下顯示單一按鈕。

  1. 按一下「Select favorite contact」(選取常用聯絡人),系統會隨即帶您前往設定活動。

設定活動的螢幕截圖,顯示有四位聯絡人可供選擇 Android 主畫面顯示淺色主題下的「Hello World」小工具

  1. 選取聯絡人。您的小工具會隨即更新。不過,小工具並未顯示您的常用聯絡人,而您將會在下一節加入此功能。

管理小工具資料

  1. 請開啟 App Inspection 工具,按需要連結至程序,然後選取「資料庫檢查器」分頁標籤,查看應用程式資料庫的內容。
  2. 在小工具中選取常用聯絡人,並確認其更新為「Hello World」。回到 App Inspection 工具,您應該會看到一個小工具條目出現在「Widget model」(小工具模型) 分頁標籤中。您可能需要重新整理表格或按「Live updates」(即時更新) 來查看變更。

dd030cce6a75be25.png

  1. 新增其他小工具並選取其他聯絡人。您可能需要按「Refresh table」(重新整理表格) 或「Live updates」(即時更新) 才能看到新模型。
  2. 移除小工具,注意在移除小工具之後,模型仍會保留在資料庫中。

您可以透過覆寫 onDeleted 來更新 SociaLiteAppWidgetReceiver,在移除小工具時清理資料庫。

如要清理孤立的小工具模型,可以呼叫 WidgetModelRepository.cleanupWidgetModels。這個存放區類別由 Hilt 管理,因此您需要使用依附元件插入功能來取得例項。

  1. SociaLiteAppWidgetReceiver 中,將 AndroidEntryPoint Hilt 註解加到接收器類別宣告中,並插入 WidgetModelRepository 例項。
  2. 在方法中呼叫 WidgetModelRepository.cleanupWidgetModels 來覆寫 onDeleted

您的程式碼應如下所示:

package com.google.android.samples.socialite.widget

import android.content.Context
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
import com.google.android.samples.socialite.widget.model.WidgetModelRepository
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class SociaLiteAppWidgetReceiver : GlanceAppWidgetReceiver() {
   override val glanceAppWidget: GlanceAppWidget = SociaLiteAppWidget()

   @Inject
   lateinit var repository: WidgetModelRepository

   override fun onDeleted(context: Context, appWidgetIds: IntArray) {
       super.onDeleted(context, appWidgetIds)
       repository.cleanupWidgetModels(context)
   }

}
  1. 重新執行應用程式。當您將小工具從主畫面中移除時,應該會看到模型行已從應用程式檢查器中移除。

5. 新增聯絡人使用者介面,並在收到新訊息時更新

您已進入本程式碼實驗室的最後一個步驟。在本節中,您將為小工具實作最終的聯絡人使用者介面,並在有未讀訊息時更新介面。

  1. 檢視模型套件中的 WidgetModelRepository 類別。

您會在這裡使用 updateUnreadMessagesForContact 便利方法;這種方法會更新與聯絡人 ID 相關聯的小工具。

//Don't add this code.
fun updateUnreadMessagesForContact(contactId: Long, unread: Boolean) {
   coroutineScope.launch {
       widgetModelDao.modelsForContact(contactId).filterNotNull().forEach { model ->
           widgetModelDao.update(
             WidgetModel(model.widgetId, model.contactId, model.displayName, model.photo, unread)
           )
           SociaLiteAppWidget().updateAll(appContext)
       }
   }
}

此方法有兩個參數:contactId 為正在更新的聯絡人 ID,unread 為布林值,表示未讀訊息狀態。此方法會使用 WidgetModelDao,找出所有顯示這個聯絡人的小工具模型,並使用新的讀取狀態更新模型。接著,這個函式會呼叫「資訊一覽」提供的 SociaLiteAppWidget().updateAll 方法,更新使用者主畫面上的所有小工具。

現在您已瞭解小工具及其狀態的更新方式,接下來就可以建立聯絡人使用者介面、傳送訊息,並觀察更新過程。為此,您需要在小工具版面配置中使用 FavoriteContact 可組合函式更新 SociaLiteAppWidget。在此版面配置中,您還需要檢查是否應顯示 No new messages 還是 New Messages!

  1. 檢視 com.google.android.samples.socialite.widget.ui 套件中的 FavoriteContact.kt 檔案。
//Don't add this code.
@Composable
fun FavoriteContact(model: WidgetModel, onClick: Action) {
   Column(
       modifier = GlanceModifier.fillMaxSize().clickable(onClick)
           .background(GlanceTheme.colors.widgetBackground).appWidgetBackground()
           .padding(bottom = 8.dp),
       verticalAlignment = Alignment.Vertical.Bottom,
       horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
   ) {
       Image(
           modifier = GlanceModifier.fillMaxWidth().wrapContentHeight().defaultWeight()
               .cornerRadius(16.dp),
           provider = ImageProvider(model.photo.toUri()),
           contentScale = ContentScale.Crop,
           contentDescription = model.displayName,
       )
       Column(
           modifier = GlanceModifier.fillMaxWidth().wrapContentHeight().padding(top = 4.dp),
           verticalAlignment = Alignment.Vertical.Bottom,
           horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
       ) {
           Text(
               text = model.displayName,
               style = TextStyle(
                   fontWeight = FontWeight.Bold,
                   fontSize = 24.sp,
                   color = (GlanceTheme.colors.onSurface),
               ),
           )

           Text(
               text = if (model.unreadMessages) "New Message!" else "No messages",
               style = TextStyle(
                   fontWeight = FontWeight.Bold,
                   fontSize = 16.sp,
                   color = (GlanceTheme.colors.onSurface),
               ),
           )
       }
   }
}
  1. SociaLiteAppWidgetContent 可組合函式的 Text("Hello World") 替換為呼叫 FavoriteContact 可組合函式。

這個可組合函式會接收 WidgetModel 和一個由 actionStartActivity「資訊一覽」函式所建立的動作。

  1. 當模型並非 WidgetModel 時,請在 ZeroState 之前加入對 when 區塊的呼叫。
when (model) {
  is WidgetModel -> FavoriteContact(model = model, onClick = actionStartActivity(
     Intent(LocalContext.current.applicationContext, MainActivity::class.java)
         .setAction(Intent.ACTION_VIEW)
         .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
         .setData("https://socialite.google.com/chat/${model.contactId}".toUri()))
  )
  else -> ZeroState(widgetId)
}
  1. 若 Android Studio 沒有自動新增以下匯入項目,請現在新增:
import com.google.android.samples.socialite.widget.ui.FavoriteContact
import androidx.glance.appwidget.action.actionStartActivity
import android.content.Intent
import com.google.android.samples.socialite.MainActivity
import androidx.core.net.toUri
  1. 執行應用程式。
  2. 選擇一位常用聯絡人,傳送訊息,並在對方回覆之前立即結束應用程式。收到回覆訊息時,小工具的狀態應會改變。
  3. 按一下小工具開啟即時通訊,然後當您返回主畫面時,應會看到狀態再次更新。

Android 主畫面,顯示已完成的淺色主題 SociaLite 小工具。

6. 恭喜

您已經成功完成本程式碼實驗室,並學會如何使用「資訊一覽」編寫小工具!您應該能輕鬆地建立精緻的小工具,讓小工具在多種主畫面上呈現出色效果、處理使用者輸入內容,並能自行更新。

如要取得 main 分支的解決方案程式碼,請按照下列步驟操作:

  1. 如已下載 SociaLite,請執行以下指令:
git checkout main
  1. 否則,請再次下載程式碼以查看 main 分支:
git clone git@github.com:android/socialite.git

瞭解詳情