【问题标题】:how to avoid getting the "android.os.TransactionTooLargeException"如何避免得到“android.os.TransactionTooLargeException”
【发布时间】:2019-04-19 20:12:10
【问题描述】:

在android应用程序中,有些情况需要传递一些数据,跨越activity/fragment,传递给服务等。它一直在使用parcelable并放入intent/bundle。它可以正常工作,只是有时会在超过 1 兆的 parcelable 限制时崩溃。

android.os.TransactionTooLargeException: data parcel size 526576 bytes

试图看看它是否可以将parcelable对象的内容放入lruCache,所以基本上用它自己的使用lruCache的实现来替换parcelable的保存/加载。

这种方法有什么问题吗?或者有什么建议/替代方案来解决这个问题?

@ApiSerializable
class  DataItem (
        @SerializedName("uuid")
        var uuid: String = "",

        @SerializedName("image")
        val mainImage: Image?,  //another parcelable type

        @SerializedName("entities")
        var entities: List<EntityInfo>?,


        //......
        // a lot of data
        //......
        //......

) : BaseDataItem(), IData {

    override fun uuid(): String {
        return uuid
    }

    //......


    constructor(parcel: Parcel) : this(
            parcel.readString(), //uuid

            //...
            //...

            parcel.readParcelable(Image::class.java.classLoader),
            mutableListOf<EntityInfo>().apply {
                parcel.readTypedList(this, EntityInfo.CREATOR)
            }) {

    }


    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(uuid ?: "")

        //......
        //......

        parcel.writeParcelable(mainImage, flags)
        parcel.writeTypedList(entities)

    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<DataItem> {
        override fun createFromParcel(parcel: Parcel): DataItem {
            return DataItem(parcel)
        }

        override fun newArray(size: Int): Array<DataItem?> {
            return arrayOfNulls(size)
        }
    }
}

方法是使用 lruCache 本身替换包裹部分的保存/加载:

    // having the cache somewhere
    val dataCache =  LruCache<String, IData>(200)

并且只有一个字符串成员与 Parcel 一起保存/加载:

    fun init (copyData: DataItem) {
        // do sopy over from the copyData
    }

    constructor(parcel: Parcel) : this() {
        uuid = parcel.readString(), //uuid

        val _thisCopy = dataCache.get(uuid)

        init(_thisCopy)

    }

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(uuid ?: "")

        dataCache.put(uuid, this)
    }

【问题讨论】:

  • 简单。不要传递对象,而只是传递对象的标识符,然后在您想要对象的另一个屏幕中,从数据库中检索它
  • 可能有一个数据列表在传递,如果对每一个项目都这样做,从数据库获取速度很慢。并且 DataItem 也可能是其他 parcelable 类的某个成员,不能简单地用“标识符”替换
  • 你错了。数据库很快。获取列表很快。如果您的列表没有标识符,那么我强烈建议您更改应用程序的整个架构。如果您是 Android 新手,请开始阅读本文developer.android.com/jetpack/docs/guide
  • "并且 DataItem 也可能是其他可打包类的某个成员,不能简单地用“标识符”替换——嗯,它必须是,因为您需要一个标识符作为您的密钥LruCache。使用缓存作为存储库的一部分是完全合理的,虽然偶尔会有点棘手。
  • 感谢@CommonsWare,是的,“标识符”是 DataItem 中的“uuid”,只是另一个 Parceable 类可以将 DataItem 作为其成员,因此该类可以执行“包裹”操作并隐式地包裹 DataItem。听起来这种方法可行但“棘手”,有什么提示可能是需要注意的棘手部分吗?

标签: android parcelable android-lru-cache


【解决方案1】:

您应该避免将包含大量数据的整个对象传递给您的 Next 活动。因此,您的对象可能有很多数据。因此,有时系统一次无法处理太多要传输的数据。尝试使用 Preferences 来存储您的对象数据并在其他活动中检索相同的数据。

请在这里回答我: Exception when starting activity android.os.TransactionTooLargeException: data parcel size

【讨论】:

  • 感谢您的建议,但 SharedPreferences 不是这里的选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-07
相关资源
最近更新 更多