You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中通过Hilt为Glance Widget注入ViewModel

解决Glance Widget中注入Hilt ViewModel的问题

由于Glance Widget的运行环境没有ViewModelStoreOwner(如Activity/Fragment这类组件),直接使用hiltViewModel()会失效,以下是可行的实现方案:

步骤1:为Widget Receiver添加Hilt注解

给CustomGlanceWidgetReceiver加上@AndroidEntryPoint,让Hilt能够管理其依赖注入:

@AndroidEntryPoint
class CustomGlanceWidgetReceiver : GlanceAppWidgetReceiver() {
    override val glanceAppWidget: GlanceAppWidget = MyAppWidget()
}

步骤2:定义Hilt EntryPoint获取ViewModel工厂

创建一个EntryPoint接口,用于从Hilt的单例组件中获取ViewModel的创建工厂:

@EntryPoint
@InstallIn(SingletonComponent::class)
interface ViewModelFactoryEntryPoint {
    fun viewModelFactory(): ViewModelProvider.Factory
}

步骤3:在Widget中创建ViewModel实例

在MyAppWidget的provideGlance方法中,通过Hilt EntryPoint获取ViewModel工厂,手动创建ViewModel实例(临时实现ViewModelStoreOwner来满足ViewModelProvider的要求):

class MyAppWidget : GlanceAppWidget() {
    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // 从Application Context获取Hilt EntryPoint
        val entryPoint = EntryPointAccessors.fromApplication(
            context.applicationContext,
            ViewModelFactoryEntryPoint::class.java
        )
        val viewModelFactory = entryPoint.viewModelFactory()

        // 创建ViewModel实例
        val viewModel = ViewModelProvider(
            object : ViewModelStoreOwner {
                private val store = ViewModelStore()
                override fun getViewModelStore(): ViewModelStore = store
            },
            viewModelFactory
        )[BaseEntryWidgetViewModel::class.java]

        provideContent {
            MyContent(viewModel)
        }
    }
}

步骤4:在Glance Composable中使用ViewModel

修改MyContent,直接接收传入的ViewModel实例并调用其方法:

@Composable
private fun MyContent(
    viewModel: BaseEntryWidgetViewModel
) {
    Column(
        modifier = GlanceModifier.fillMaxSize(),
        verticalAlignment = Alignment.Top,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Row(horizontalAlignment = Alignment.CenterHorizontally) {
            TextField(value = "", onValueChange = {}, label = {
                Text(text = "Title")
            })
            TextField(value = "", onValueChange = {}, label = {
                Text(text = "Amount")
            })
            Button(
                text = "Save",
                onClick = { 
                    // 调用ViewModel的业务方法
                    // viewModel.saveEntry(...)
                }
            )
            Button(
                text = "Work",
                onClick = {
                    // viewModel.doWork()
                }
            )
        }
    }
}

注意事项

  • 每次Widget更新时provideGlance都会被调用,ViewModel实例也会重新创建。如果需要持久化状态,建议将数据存储到Room、SharedPreferences等介质中。
  • 确保你的Application类已添加@HiltAndroidApp注解,这是Hilt工作的基础:
@HiltAndroidApp
class MyApplication : Application()

内容的提问来源于stack exchange,提问作者geontricks developer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 16:05:35