将数据从挂起的意图传递到 BroadcastReceiver (AlarmManager)



我一直在玩本地通知。 我正在尝试将数据传递给广播接收器;我注意到下面的代码适用于棒棒糖,但是在我的 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<MyData>("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:代码缓存收集后,代码=45KB,数据=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的编译代码分配了61KB。(android.content.Context, android.util.AttributeSet, int, 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:执行完整的代码缓存收集,代码=111KB,数据=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:代码缓存收集后,代码=71KB,数据=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 检测 05-19 21:07:04.396 8150-8157/com.wolfbane.example W/art:挂起所有线程占用:10.531ms

我找到了艾萨克·乔丹的解决方案

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

将数据添加到意向时:

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

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

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

ParcelableUtil in Kotlin

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
}
}

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

  1. 错误但简单的方法:将可包裹对象放入一个捆绑包中,并将捆绑包作为插入意图的对象:
intent.putExtra("data", Bundle().also { it.putParcelable("realData", theParcelableObject) })

并稍后查询捆绑包:

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

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

  1. 正确的方法:将数据保存到 DB 中,然后只将对象的 ID 放入 Intent,要获取数据,请使用 DB 执行查询。缺点是工作量更大,需要数据库管理。优点是,假设您很好地管理数据库,它是面向未来的。

相关内容

  • 没有找到相关文章

最新更新