【问题标题】:Passing data to a BroadcastReceiver from a PendingIntent (AlarmManager)从 PendingIntent (AlarmManager) 向 BroadcastReceiver 传递数据
【发布时间】:2017-05-19 18:56:38
【问题描述】:

我一直在玩本地通知。我正在尝试将数据传递给广播接收器;我注意到下面的代码适用于棒棒糖,但在我的 Nexus 6P 和 7.1 上却不行。

这就是我设置意图并添加“额外”数据的方式:

val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val alarmIntent = Intent(context, AlarmReceiver::class.java)
alarmIntent.putExtra("data", data)
val pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT)
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), (1000 * 60).toLong(), pendingIntent) // Millisec * Second * Minute

在广播接收器中:

val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
    val wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "")
    wl.acquire()
    val data = intent.getParcelableExtra<MyData>("data")

谷歌搜索这个问题并没有带来太多,它带来的是一个 SO 帖子,以及一个提到这个确切问题的评论。但是我没有看到任何解决方案,而且我尝试过的方法也不起作用,所以我想知道是否有人想出一种可以在 7.1 上运行的方法?

编辑:

这是数据对象:

data class MyData(val accountNumber: String, val date: Date, val key: Int) : Parcelable {
companion object {
    @JvmField val CREATOR: Parcelable.Creator< MyData > = object : Parcelable.Creator< MyData > {
        override fun createFromParcel(source: Parcel): MyData = MyData(source)
        override fun newArray(size: Int): Array< MyData?> = arrayOfNulls(size)
    }
}

constructor(source: Parcel) : this(
        source.readString(),
        source.readSerializable() as Date,
        source.readInt()
)

override fun describeContents() = 0

override fun writeToParcel(dest: Parcel, flags: Int) {
    dest.writeString(accountNumber)
    dest.writeSerializable(date)
    dest.writeSerializable(key)
}

}

调用val data = intent.getParcelableExtra&lt;MyData&gt;("data")时的日志摘录

05-19 21:06:37.076 8150-8220/com.wolfbane.example V/FA:活动恢复,时间:864865 05-19 21:06:37.098 8150-8154/com.wolfbane.example I/art:做部分代码缓存收集,代码=47KB,数据=47KB 05-19 21:06:37.098 8150-8154/com.wolfbane.example I/art: 代码缓存收集后,code=45KB, data=46KB 05-19 21:06:37.098 8150-8154/com.wolfbane.example I/art: 将代码缓存容量增加到 256KB 05-19 21:06:37.102 8150-8154/com.wolfbane.example I/art: JIT 为 void android.widget.TextView.(android.content.Context, android.util.AttributeSet, int,诠释) 05-19 21:06:37.102 8150-8154/com.wolfbane.example I/art: 编译器分配 4MB 来编译 void android.widget.TextView.(android.content.Context, android.util.AttributeSet, int, int) 05-19 21:06:37.151 8150-8154/com.wolfbane.example I/art:做全码缓存收集,code=111KB,data=79KB 05-19 21:06:37.151 8150-8154/com.wolfbane.example I/art: 启动阻塞GC JitCodeCache 05-19 21:06:37.151 8150-8154/com.wolfbane.example I/art:代码缓存收集后,code=71KB,data=40KB 05-19 21:06:42.079 8150-8220/com.wolfbane.example V/FA:不活动,断开服务 05-19 21:06:42.829 8150-8157/com.wolfbane.example I/art:启动阻塞 GC Instrumentation 05-19 21:07:04.396 8150-8157/com.wolfbane.example W/art: 暂停所有线程耗时: 10.531ms

【问题讨论】:

  • 您是否只是收到来自意图的null?另外,你确定你传递的数据是Parcelable
  • 是的,这是正确的,它始终为空。是的,它是可包裹的。请注意,它适用于 Lollipop,没有任何问题。
  • 数据对象是Parcelable吗?
  • 我已经用 Data 类更新了问题。
  • 要么您的意图中没有额外内容(intent.getExtras()null),要么在解开您的 MyData 对象时引发某种错误。当您的应用调用val data = intent.getParcelableExtra&lt;MyData&gt;("data") 时可以显示 LogCat 吗?操作系统可能会发出警告。

标签: android kotlin


【解决方案1】:

有两种方法可以做到这一点:

  1. 错误但简单的方法:将 Parcelable 对象放入一个包中,并将该包作为要插入 Intent 的对象:
intent.putExtra("data", Bundle().also { it.putParcelable("realData", theParcelableObject) })

稍后再查询捆绑包:

val obj = intent.getBundleExtra("data")?.getParcelable<MyData>("realData")

为什么这是错误的?因为该类可能会在应用程序的下一个版本中发生变化,并且您的 PendingIntent 可能会被捕获,而不是当前版本。这可能会导致您丢失数据。

  1. 正确方法:将数据保存到DB中,将对象的ID放入Intent中,获取数据通过DB查询。缺点是工作量大,需要数据库管理。优点是它是面向未来的,前提是您管理好数据库。

【讨论】:

    【解决方案2】:

    我通过Isaac Jordan找到了解决方案

    它的要点是传递一个字节数组作为“额外”,而不是你的 Parcelable 类,即

    将数据添加到意图时:

    val bytes = ParcelableUtil.marshall(data)
    alarmIntent.putExtra("data", bytes)
    

    然后在接收端,您将按如下方式读取数据:

    val bytes = intent.getByteArrayExtra("data")
    val data = MyData(ParcelableUtil.unmarshal(bytes))
    

    Kotlin 中的 ParcelableUtil

    class ParcelableUtil {
    companion object {
        fun marshall(parcelable: Parcelable): ByteArray {
            val parcel = Parcel.obtain()
            parcelable.writeToParcel(parcel, 0)
            val bytes = parcel.marshall()
            parcel.recycle()
            return bytes
        }
    
        fun unmarshall(bytes: ByteArray): Parcel {
            val parcel = Parcel.obtain()
            parcel.unmarshall(bytes, 0, bytes.size)
            parcel.setDataPosition(0)
            return parcel
        }
    
        fun <T> unmarshall(bytes: ByteArray, creator: Parcelable.Creator<T>): T {
            val parcel = unmarshall(bytes)
            val result = creator.createFromParcel(parcel)
            parcel.recycle()
            return result
        }
    }
    

    【讨论】:

    • 我如何在一个有“Parcelize”注释的类上使用 unmarshal?
    猜你喜欢
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多