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

AppWidgetProvider onReceive传递Serializable对象时Extras为空问题

Android Widget传递Serializable对象时Extras为空的解决方案

核心原因

RemoteViews的FillInIntent对Serializable对象的传递有多重限制:

  • 序列化类的实现不规范(缺少serialVersionUID、成员变量不可序列化)
  • 对象大小超过系统限制(通常为1MB)
  • PendingIntent的FLAG设置导致Extras合并失败

分步解决

1. 规范Serializable类的实现

确保你的ExampleItem类严格符合序列化要求,这是最容易忽略的关键点:

class ExampleItem : Serializable {
    // 必须显式声明serialVersionUID,避免版本不一致导致解析失败
    companion object {
        private const val serialVersionUID = 1L
    }

    // 所有成员变量必须是可序列化的(基本类型、String、或实现Serializable的类)
    val id: Int = 0
    val name: String = ""
    // 嵌套对象必须也实现Serializable
    val nestedItem: NestedItem? = null

    class NestedItem : Serializable {
        private const val serialVersionUID = 2L
        val value: String = ""
    }
}

2. 调整PendingIntent的FLAG设置

原代码中FLAG_UPDATE_CURRENT是正确的,但要适配Android 12+的Mutable/ Immutable规则,同时保证模板Intent的Extras尽量简洁:

// onUpdate方法中
val intent = Intent(context, WidgetProvider::class.java).apply {
    action = Constants.Widget.ACTION
    // 只传递必要的Widget ID,避免冗余Extras干扰合并逻辑
    putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
}
val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
} else {
    PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
widgetViews.setPendingIntentTemplate(R.id.widget_listView, pendingIntent)

3. 改用ByteArray传递Serializable对象(最可靠方案)

如果直接传递Serializable仍失败,转成ByteArray可以绕过系统的自动过滤逻辑:

在WidgetFactory中打包对象:

val fillInIntent = Intent().apply {
    // 将Serializable对象转成ByteArray
    val bos = ByteArrayOutputStream()
    val oos = ObjectOutputStream(bos)
    oos.writeObject(item)
    oos.flush()
    putExtra(Constants.Widget.ITEM_BYTES, bos.toByteArray())
    // 基本类型可正常传递
    putExtra(Constants.IntentItemPosition, 67)
}
itemView.setOnClickFillInIntent(R.id.widgetItemButton, fillInIntent)

在AppWidgetProvider的onReceive中解析:

override fun onReceive(context: Context, intent: Intent) {
    super.onReceive(context, intent)
    when (intent.action) {
        Constants.Widget.ACTION -> {
            val itemBytes = intent.getByteArrayExtra(Constants.Widget.ITEM_BYTES)
            itemBytes?.let {
                val bis = ByteArrayInputStream(it)
                val ois = ObjectInputStream(bis)
                val exampleItem = ois.readObject() as? ExampleItem
                ois.close()
                exampleItem?.let {
                    // 处理业务逻辑
                }
            }
            // 获取基本类型参数
            val position = intent.getIntExtra(Constants.IntentItemPosition, -1)
        }
    }
}

4. 避免强制拆包

永远不要用!!强制转换,先做空判断防止崩溃:

// 错误写法
exampleItem!!.let { ... }

// 正确写法
exampleItem?.let { 
    // 处理逻辑
} ?: run {
    Log.e("Widget", "ExampleItem序列化失败或为空")
}

额外注意事项

  • 传递的Serializable对象大小不要超过1MB,否则系统会自动丢弃该Extra
  • RemoteViews不支持Parcelable跨进程传递,不要尝试用Parcelable替代Serializable
  • 测试时可打印Extras的大小和内容,确认是否被系统过滤

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 13:35:18