Android桌面Widget中fillInIntent无法传递数据问题排查
问题
桌面Widget中的ListView点击列表项时,无法获取fillInIntent传入的数据,始终拿到默认值0。已为每个列表项设置fillInIntent,并配置了触发Widget广播接收器的PendingIntent模板,尝试添加FILL_IN_COMPONENT标识也无效。
代码如下:
class WidgetProvider : HomeWidgetProvider() { override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, widgetData: SharedPreferences) { appWidgetIds.forEach { widgetId -> val views = RemoteViews(context.packageName, R.layout.widget_layout).apply { val todosStr = widgetData.getString("todos", "null") val todos = ArrayList<HashMap<String, Any>>() val todosRemoteView = RemoteViews.RemoteCollectionItems.Builder() if(todosStr != "null"){ val jObj = JSONObject(todosStr) val jsonArry = jObj.getJSONArray("todos") for (i in 0 until jsonArry.length()) { val todo = HashMap<String, Any>() val obj = jsonArry.getJSONObject(i) todo["id"] = obj.getInt("id") todos.add(todo) val view = RemoteViews(context.packageName, R.layout.each_todo).apply { setTextViewText(R.id.each_todo_container_text, todo["taskName"].toString()) val fillInIntent = Intent().apply { Bundle().also { extras -> extras.putInt("todo_id", todo["id"].toString().toInt())//this isn't working for some reason putExtras(extras) } } Log.d("debugging", "id received is ${todo["id"].toString()}" ) setOnClickFillInIntent(R.id.each_todo_container_text, fillInIntent) } todosRemoteView.addItem(todo["id"].toString().toInt().toLong(), view) } } setRemoteAdapter( R.id.todos_list, todosRemoteView .build() ) val pendingIntentx: PendingIntent = Intent( context, WidgetProvider::class.java ).run { PendingIntent.getBroadcast(context, 0, this, PendingIntent.FLAG_IMMUTABLE or Intent.FILL_IN_COMPONENT) } setPendingIntentTemplate(R.id.todos_list, pendingIntentx) } appWidgetManager.updateAppWidget(widgetId, views) } } override fun onReceive(context: Context?, intent: Intent?) { val viewIndex: Int = intent!!.getIntExtra("todo_id", 0) Log.d("debugging", "an item is clicked $viewIndex") //the default value gets used, which means that the receiver isn't receiving the intent data super.onReceive(context, intent) } }
解决方案
问题根源
- 错误的填充标识:使用
Intent.FILL_IN_COMPONENT是错误的,该标识用于填充组件信息(如目标类),但你需要填充的是额外数据(Extras),应该替换为Intent.FILL_IN_EXTRAS。 - fillInIntent绑定到子View:将
fillInIntent绑定到了TextView子控件上,导致点击时数据无法正确合并到模板Intent中,应该绑定到列表项的根布局。 - PendingIntent复用冲突:使用固定的requestCode(0)可能导致不同Widget实例的PendingIntent复用,引发数据异常。
修改后的代码
class WidgetProvider : HomeWidgetProvider() { override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, widgetData: SharedPreferences) { appWidgetIds.forEach { widgetId -> val views = RemoteViews(context.packageName, R.layout.widget_layout).apply { val todosStr = widgetData.getString("todos", "null") val todosRemoteView = RemoteViews.RemoteCollectionItems.Builder() if (todosStr != "null") { val jObj = JSONObject(todosStr) val jsonArry = jObj.getJSONArray("todos") for (i in 0 until jsonArry.length()) { val obj = jsonArry.getJSONObject(i) val todoId = obj.getInt("id") val taskName = obj.getString("taskName") // 修复taskName未赋值的问题 val view = RemoteViews(context.packageName, R.layout.each_todo).apply { setTextViewText(R.id.each_todo_container_text, taskName) // 简化fillInIntent的创建 val fillInIntent = Intent().apply { putExtra("todo_id", todoId) } Log.d("debugging", "设置的id是 $todoId") // 绑定到列表项的根布局(需确保each_todo.xml的根布局有id:each_todo_root) setOnClickFillInIntent(R.id.each_todo_root, fillInIntent) } todosRemoteView.addItem(todoId.toLong(), view) } } setRemoteAdapter(R.id.todos_list, todosRemoteView.build()) // 创建正确的PendingIntent模板 val templateIntent = Intent(context, WidgetProvider::class.java) val pendingIntentx = PendingIntent.getBroadcast( context, widgetId, // 用widgetId作为requestCode,避免复用冲突 templateIntent, PendingIntent.FLAG_IMMUTABLE or Intent.FILL_IN_EXTRAS ) setPendingIntentTemplate(R.id.todos_list, pendingIntentx) } appWidgetManager.updateAppWidget(widgetId, views) } } override fun onReceive(context: Context?, intent: Intent?) { val todoId = intent?.getIntExtra("todo_id", 0) ?: 0 Log.d("debugging", "点击的项id是 $todoId") super.onReceive(context, intent) } }
额外注意事项
- 确保
each_todo.xml的根布局添加唯一id(如android:id="@+id/each_todo_root"),否则无法绑定fillInIntent到根布局。 - 修复了原代码中
taskName未赋值的问题,避免空指针异常。 - 使用
widgetId作为PendingIntent的requestCode,确保每个Widget实例的模板Intent独立,避免复用导致的数据错误。
内容的提问来源于stack exchange,提问作者Pro
相关产品推荐
相关产品推荐

