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

如何向Android GlanceWorker注入运行时才确定的参数?

向GlanceWorker传递运行时动态参数的解决方案

核心思路

因为myObject(GlanceStateDefinition<T>)和myClass(Class<out WidgetAbstractClass>)是根据触发回调的小部件动态确定的,没法提前注入到WorkerFactory,所以采用传递类名字符串到WorkRequest输入数据,再在Worker内部反射还原实例的方案,适配运行时参数需求。

具体实现

1. 修改Action类,传递类名参数

在构建OneTimeWorkRequest时,把myObject和myClass的类名加入输入数据:

abstract class Action<T : ShowPortfolioMenuState<T>>(
    val myObject: GlanceStateDefinition<T>,
    val myClass: Class<out WidgetAbstractClass>,
) : ActionCallback {

    override suspend fun onAction(
        context: Context,
        glanceId: GlanceId,
        parameters: ActionParameters,
    ) {
        val glanceIdInt = GlanceAppWidgetManager(context).getAppWidgetId(glanceId)
        val showMenu = parameters[ActionParameters.Key("showMenu")] ?: false

        val glanceWork =
            OneTimeWorkRequest.Builder(GlanceWorkerPortfolioChange::class.java)
                .setInputData(
                    workDataOf(
                        "GLANCE_ID" to glanceIdInt,
                        "SHOW_MENU" to showMenu,
                        // 传递GlanceStateDefinition的类名
                        "STATE_DEFINITION_CLASS" to myObject.javaClass.name,
                        // 传递Widget类的类名
                        "WIDGET_CLASS" to myClass.name
                    )
                ).build()

        WorkManager.getInstance(context)
            .beginUniqueWork("Worker Name",
                ExistingWorkPolicy.REPLACE,
                glanceWork
            ).enqueue()
    }
}

2. 调整GlanceWorker,解析参数并执行逻辑

移除构造器中无法注入的参数,改为在doWork里通过反射还原实例,处理泛型擦除问题:

@HiltWorker
class GlanceWorker @AssistedInject constructor(
    @Assisted val context: Context,
    @Assisted workerParameters: WorkerParameters,
): CoroutineWorker(context, workerParameters) {
    
    override suspend fun doWork(): Result {
        val glanceIdInt = inputData.getInt("GLANCE_ID", -1)
        val glanceId = GlanceAppWidgetManager(context).getGlanceIdBy(glanceIdInt)
        val showMenu = inputData.getBoolean("SHOW_MENU", false)
        
        // 读取输入的类名字符串,为空则直接返回失败
        val stateDefClassName = inputData.getString("STATE_DEFINITION_CLASS") ?: return Result.failure()
        val widgetClassName = inputData.getString("WIDGET_CLASS") ?: return Result.failure()
        
        return try {
            // 加载GlanceStateDefinition类并获取实例(如果是单例,用getField("INSTANCE").get(null)更高效)
            val stateDefClass = Class.forName(stateDefClassName) as Class<GlanceStateDefinition<*>>
            val myObject = stateDefClass.getDeclaredConstructor().newInstance() as GlanceStateDefinition<ShowMenuState<*>>
            
            // 加载Widget类
            val myClass = Class.forName(widgetClassName) as Class<out WidgetAbstractClass>
            
            // 执行小部件更新逻辑
            myClass.apply {
                @Suppress("UNCHECKED_CAST")
                updateAppWidgetState(context, myObject as GlanceStateDefinition<ShowMenuState<Any>>, glanceId) { state ->
                    (state as ShowMenuState<*>).updateShowMenu(showMenu)
                }
                update(context, glanceId)
            }
            Result.success()
        } catch (e: Exception) {
            e.printStackTrace()
            Result.failure()
        }
    }
}

注意事项

  • 如果你的GlanceStateDefinition是单例实现(比如用object声明),可以把实例获取逻辑改成stateDefClass.getField("INSTANCE").get(null),避免反射调用构造方法的开销。
  • 代码中的@Suppress("UNCHECKED_CAST")是因为泛型信息在运行时被擦除,只要确保传递的类名对应正确的类型,这个转换就是安全的。
  • 这种方案不需要自定义WorkerFactory,完全依赖WorkRequest的输入数据传递动态参数,适配不同小部件的差异化需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 14:35:23