Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ComposeでWidgetを実装できるライブラリ「Glance」がbetaになったので触ってみる / Glance is now in beta

ComposeでWidgetを実装できるライブラリ「Glance」がbetaになったので触ってみる / Glance is now in beta

https://zozotech-inc.connpass.com/event/287354/

[Android] ComposeでWidgetを実装できるライブラリ「Glance」がbetaになったので触ってみる

T.Nonomura

July 11, 2023
Tweet

Other Decks in Programming

Transcript

  1. ComposeでWidgetを実装できるライブ
    ラリ「Glance」がbetaになったので触っ
    てみる

    ZOZO Tech Meetup - iOS/Android (2023/07/11)

    株式会社ZOZO

    ブランドソリューション開発本部 フロントエンド部 WEARAndroidブロック

    ブロック長

    野々村 樹
    Copyright © ZOZO, Inc.
    1

    View Slide

  2. © ZOZO, Inc.
    株式会社ZOZO

    ブランドソリューション開発本部 フロントエンド部 WEARAndroidブロッ
    ク

    ブロック長
    野々村 樹

    Twitter:@nono_develop

    2023年入社

    3歳の娘がいます

    趣味はゲーム、謎解き

    2

    View Slide

  3. © ZOZO, Inc.
    話すこと

    3
    ● 従来のWidgetについてざっくりと

    ● Glanceとは

    ● 実際にGlanceを触ってみる

    ● betaの変更点

    ● 更新処理の無限ループ問題

    ● まとめ


    View Slide

  4. © ZOZO, Inc.
    話さないこと

    4
    ● 従来のWidgetについての詳細

    ● Jetpack Composeに関する説明


    View Slide

  5. © ZOZO, Inc.
    話すこと

    5
    ● 従来のWidgetについてざっくりと

    ● Glanceとは

    ● 実際にGlanceを触ってみる

    ● betaの変更点

    ● 更新処理の無限ループ問題

    ● まとめ


    View Slide

  6. © ZOZO, Inc.
    Widget使ってますか?

    6

    View Slide

  7. © ZOZO, Inc.
    7
    Android版 WEARアプリのWidget

    View Slide

  8. © ZOZO, Inc.
    従来のWidgetについてざっくりと



    ● レイアウトをXMLで定義する

    ○ レイアウトはRemoteViewsをベースとしている

    ● AppWidgetProviderクラスでWidgetのブロードキャストを処理する

    8

    View Slide

  9. © ZOZO, Inc.
    話すこと

    9
    ● 従来のWidgetについてざっくりと

    ● Glanceとは

    ● 実際にGlanceを触ってみる

    ● betaの変更点

    ● 更新処理の無限ループ問題

    ● まとめ


    View Slide

  10. © ZOZO, Inc.
    話すこと

    10
    ● 従来のWidgetについてざっくりと

    ● Glanceとは

    ● 実際にGlanceを触ってみる

    ● betaの変更点

    ● 更新処理の無限ループ問題

    ● まとめ


    View Slide

  11. © ZOZO, Inc.
    Glanceとは


    ● Compose RuntimeのAPI

    ● Composeと同様の構文でWidgetを作成することができる

    ○ 内部的にRemoteViewに変換

    11

    View Slide

  12. © ZOZO, Inc.
    話すこと

    12
    ● 従来のWidgetについてざっくりと

    ● Glanceとは

    ● 実際にGlanceを触ってみる

    ● betaの変更点

    ● 更新処理の無限ループ問題

    ● まとめ


    View Slide

  13. © ZOZO, Inc.
    話すこと

    13
    ● 従来のWidgetについてざっくりと

    ● Glanceとは

    ● 実際にGlanceを触ってみる

    ● betaの変更点

    ● 更新処理の無限ループ問題

    ● まとめ


    View Slide

  14. © ZOZO, Inc.
    14
    実際にGlanceを使って作成したWidget


    View Slide

  15. © ZOZO, Inc.
    dependencies {
    implementation("androidx.glance:glance-appwidget:1.0.0-beta01")
    }

    15
    依存関係の宣言


    View Slide

  16. © ZOZO, Inc.
    class MyGlanceAppWidget : GlanceAppWidget() {
    override suspend fun provideGlance(context: Context, id: GlanceId) {
    // Widgetのレンダリングに必要なデータを読み込む
    // 時間がかかる操作を実行する場合はwithContextで別スレッドに切り替えること
    provideContent {
    // ComposeでWidgetを作成
    HelloGlance()
    }
    }
    }
    16
    GlanceAppWidget


    View Slide

  17. © ZOZO, Inc.
    @Composable
    fun HelloGlance() {
    Box(
    modifier = GlanceModifier.fillMaxSize()
    .background(Color.White),
    contentAlignment = Alignment.Center
    ) {
    Text(
    text = "Hello Glance!",
    style = TextStyle(
    fontWeight = FontWeight.Bold,
    fontSize = 24.sp
    )
    )
    }
    }
    17
    Compose部分


    View Slide

  18. © ZOZO, Inc.
    @Composable
    fun HelloGlance() {
    Box(
    modifier = GlanceModifier.fillMaxSize()
    .background(Color.White),
    contentAlignment = Alignment.Center
    ) {
    Text(
    text = "Hello Glance!",
    style = TextStyle(
    fontWeight = FontWeight.Bold,
    fontSize = 24.sp
    )
    )
    }
    }
    18
    Compose部分

    import androidx.glance.text.Text

    View Slide

  19. © ZOZO, Inc.
    class MyGlanceAppWidgetReceiver : GlanceAppWidgetReceiver() {
    override val glanceAppWidget: GlanceAppWidget
    get() = MyGlanceAppWidget()
    }
    19
    GlanceAppWidgetReceiver


    View Slide

  20. © ZOZO, Inc.
    20
    android:name=".MyGlanceAppWidgetReceiver"
    android:exported="true">



    android:name="android.appwidget.provider"
    android:resource="@xml/my_glance_app_widget_info" />

    AndroidManifest.xml


    View Slide

  21. © ZOZO, Inc.
    21
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:updatePeriodMillis="0"
    android:initialLayout="@layout/glance_default_loading_layout"
    android:configure="com.example.android.ExampleAppWidgetConfigure"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen">

    メタデータ追加


    View Slide

  22. © ZOZO, Inc.
    initialLayout

    22
    @layout/glance_default_loading_layout

    指定なし


    View Slide

  23. © ZOZO, Inc.
    話すこと

    23
    ● 従来のWidgetについてざっくりと

    ● Glanceとは

    ● 実際にGlanceを触ってみる

    ● betaの変更点

    ● 更新処理の無限ループ問題

    ● まとめ


    View Slide

  24. © ZOZO, Inc.
    話すこと

    24
    ● 従来のWidgetについてざっくりと

    ● Glanceとは

    ● 実際にGlanceを触ってみる

    ● betaの変更点

    ● 更新処理の無限ループ問題

    ● まとめ


    View Slide

  25. © ZOZO, Inc.
    GlanceTheme

    @Composable
    fun GlanceTheme(
    colors: ColorProviders = LocalColors.current,
    content: @GlanceComposable @Composable () -> Unit
    ) {
    CompositionLocalProvider(
    LocalColors provides colors,
    content = content
    )
    }

    25
    GlanceTheme.kt
    引用 : https://android.googlesource.com/platform/frameworks/support/+/bd66997874293bcf20cfaf6e7d20633d15cefb62/glance/glance/src/main/java/androidx/glance/GlanceTheme.kt

    View Slide

  26. © ZOZO, Inc.
    GlanceTheme

    dependencies {
    // Material 2
    implementation "androidx.glance:glance-material:1.0.0-beta01"
    // Material 3
    implementation "androidx.glance:glance-material3:1.0.0-beta01"
    }
    26

    View Slide

  27. © ZOZO, Inc.
    FontFamilyのサポート

    Cursive

    27
    Monospace


    View Slide

  28. © ZOZO, Inc.
    FontFamilyのサポート

    SansSerif

    28
    Serif



    View Slide

  29. © ZOZO, Inc.
    更新のメカニズムをWorkManagerに移行

    Widget更新の際に、セッション管理にWorkManager
    が使用されるようになった

    29

    View Slide

  30. © ZOZO, Inc.
    更新のメカニズムをWorkManagerに移行

    internal suspend fun update(
    context: Context,
    appWidgetId: Int,
    options: Bundle? = null,
    ) {
    Tracing.beginGlanceAppWidgetUpdate()
    val glanceId = AppWidgetId(appWidgetId)
    if (!sessionManager.isSessionRunning(context, glanceId.toSessionKey())) {
    sessionManager.startSession(context, AppWidgetSession(this, glanceId, options))
    } else {
    val session = sessionManager.getSession(glanceId.toSessionKey()) as AppWidgetSession
    session.updateGlance()
    }
    }

    30
    GlanceAppWidget.kt
    引用 : https://android.googlesource.com/platform/frameworks/support/+/bd66997874293bcf20cfaf6e7d20633d15cefb62/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidget.kt

    View Slide

  31. © ZOZO, Inc.
    更新のメカニズムをWorkManagerに移行

    override suspend fun startSession(context: Context, session: Session) {
    if (DEBUG) Log.d(TAG, "startSession(${session.key})")
    synchronized(sessions) {
    sessions.put(session.key, session)
    }?.close()
    val workRequest = OneTimeWorkRequest.Builder(workerClass)
    .setInputData(
    workDataOf(
    keyParam to session.key
    )
    )
    .build()
    WorkManager.getInstance(context)
    .enqueueUniqueWork(session.key, ExistingWorkPolicy.REPLACE, workRequest)
    .result.await()
    enqueueDelayedWorker(context)
    }

    31
    SessionManager.kt
    引用 : https://android.googlesource.com/platform/frameworks/support/+/bd66997874293bcf20cfaf6e7d20633d15cefb62/glance/glance/src/main/java/androidx/glance/session/SessionManager.kt

    View Slide

  32. © ZOZO, Inc.
    更新のメカニズムをWorkManagerに移行

    これに伴って、Widget描画のエントリーポイントが変更

    32
    class MyGlanceAppWidget : GlanceAppWidget() {
    @Composable
    override fun Content() {
    HelloGlance()
    }
    }
    class MyGlanceAppWidget : GlanceAppWidget() {
    override suspend fun provideGlance(context: Context, id: GlanceId) {
    provideContent {
    HelloGlance()
    }
    }
    }
    alpha beta

    View Slide

  33. © ZOZO, Inc.
    話すこと

    33
    ● 従来のWidgetについてざっくりと

    ● Glanceとは

    ● 実際にGlanceを触ってみる

    ● betaの変更点

    ● 更新処理の無限ループ問題

    ● まとめ


    View Slide

  34. © ZOZO, Inc.
    話すこと

    34
    ● 従来のWidgetについてざっくりと

    ● Glanceとは

    ● 実際にGlanceを触ってみる

    ● betaの変更点

    ● 更新処理の無限ループ問題

    ● まとめ


    View Slide

  35. © ZOZO, Inc.
    AppWidgetProviderのonUpdate()無限ループ問題について


    AppWidgetProvider.onUpdate()でWorkManagerを起動す
    ると、onUpdate()が呼び出され無限ループに陥る


    35
    https://issuetracker.google.com/issues/115575872

    View Slide

  36. © ZOZO, Inc.
    AppWidgetProviderのonUpdate()無限ループ問題について


    36
    AppWidgetProvider
    onUpdate()
    WorkManager
    起動
    RescheduleReceiver
    スケジューリング
    ACTION_PACKAGE_CHANGEDがブロードキャストされ、onUpdate()が発火

    View Slide

  37. © ZOZO, Inc.
    AppWidgetProviderのonUpdate()無限ループ問題について


    37
    AppWidgetProvider
    onUpdate()
    WorkManager
    起動
    RescheduleReceiver
    スケジューリング
    ACTION_PACKAGE_CHANGEDがブロードキャストされ、onUpdate()が発火

    View Slide

  38. © ZOZO, Inc.
    対応策

    ● onUpdate()ではなくonEnabled()で定期実行する

    ● Pending状態のリクエストを用意しておく

    ○ 遠い未来に実行されるダミーのリクエストをonEnabled()
    で実行する

    38

    View Slide

  39. © ZOZO, Inc.
    Glanceでは…?

    GlanceAppWidgetReceiverはAppWidgetProviderを継承して
    いる

    39
    無限ループ問題が発生するはずだが…


    View Slide

  40. © ZOZO, Inc.
    Glanceでは…?

    GlanceAppWidgetReceiverはAppWidgetProviderを継承して
    いる

    40
    無限ループ問題が発生するかと思いきや…

    実験した限りでは発生しなかった…!
    けどソースコードを見る限りは
    修正されていなさそう

    しい

    View Slide

  41. © ZOZO, Inc.
    話すこと

    41
    ● 従来のWidgetについてざっくりと

    ● Glanceとは

    ● 実際にGlanceを触ってみる

    ● betaの変更点

    ● 更新処理の無限ループ問題

    ● まとめ


    View Slide

  42. © ZOZO, Inc.
    話すこと

    42
    ● 従来のWidgetについてざっくりと

    ● Glanceとは

    ● 実際にGlanceを触ってみる

    ● betaの変更点

    ● 更新処理の無限ループ問題

    ● まとめ


    View Slide

  43. © ZOZO, Inc.
    まとめ

    ● GlanceはComposeでWidgetを構成することができるよ

    ● ただし使えるCompose APIはGlance専用のものになるので、多
    少制限はあるよ

    ● まだbetaなので、stableが楽しみ


    43

    View Slide

  44. © ZOZO, Inc.
    ご清聴ありがとうございました

    44

    View Slide

  45. View Slide