как избежать получения исключения android.os.TransactionTooLargeException

В приложении для Android бывают случаи, когда необходимо передать некоторые данные, пересечь активность/фрагмент, перейти к сервису и т. д. Он использует пакет и помещает его в намерение/пакет. Он работает нормально, за исключением того, что иногда происходит сбой при превышении лимита в один мегабайт.

android.os.TransactionTooLargeException: data parcel size 526576 bytes

Попытка увидеть, может ли он поместить содержимое посылаемого объекта в lruCache, поэтому в основном заменяет сохранение/загрузку посылочного объекта своей собственной реализацией использования lruCache.

Есть ли у этого подхода какие-либо проблемы? Или любое предложение/альтернатива для решения проблемы?

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

person lannyf    schedule 19.04.2019    source источник
comment
Простой. Не передавайте объекты, а только идентификатор объекта, затем на другом экране, где вы хотите получить объект, извлеките его из своей базы данных.   -  person Zun    schedule 19.04.2019
comment
может быть список передаваемых данных, получение из базы данных происходит медленно, если делать это для каждого отдельного элемента. и DataItem также может быть некоторым членом другого класса, который может быть разделен, его нельзя просто заменить идентификатором   -  person lannyf    schedule 19.04.2019
comment
Ты не прав. Базы данных работают быстро. Получение списка происходит быстро. Если в вашем списке нет идентификатора, я настоятельно рекомендую вам изменить всю архитектуру вашего приложения. Начните читать это, если вы новичок в Android developer.android.com/jetpack/docs/guide   -  person Zun    schedule 19.04.2019
comment
и DataItem также может быть некоторым членом другого класса, который может быть разделен, и его нельзя просто заменить идентификатором - ну, это должно быть, поскольку вам нужен идентификатор в качестве ключа к вашему LruCache. Использование кеша как части репозитория вполне разумно, хотя иногда и немного сложно сделать это правильно.   -  person CommonsWare    schedule 19.04.2019
comment
Спасибо @CommonsWare, да, идентификатор - это uuid внутри DataItem, просто другой класс Parceable может иметь DataItem в качестве своего члена, поэтому этот класс может выполнять операцию «посылки» и неявно также упаковывать DataItem. И кажется, что этот подход выполним, но сложен, любой намек на то, что может быть сложной частью, на которую следует обратить внимание?   -  person lannyf    schedule 19.04.2019
comment
@ZUNJAE, база данных намного медленнее, чем кеш памяти.   -  person lannyf    schedule 19.04.2019
comment
Вам необходимо убедиться, что вы обновляете или аннулируете кэш при внесении изменений в базу данных. И вам нужно убедиться, что любые реактивные подходы, которые вы используете (RxJava, LiveData и т. д.), испускают измененные объекты, когда они меняются на любых активных подписчиков/наблюдателей.   -  person CommonsWare    schedule 19.04.2019
comment
@CommonsWare, хороший момент, рассмотрю эти варианты использования, спасибо!   -  person lannyf    schedule 19.04.2019
comment
Да, база данных может быть медленнее, чем кеш памяти, но при использовании пакетов вы сохраняете свои объекты на диске. Это добавляет ненужные накладные расходы. Это напоминает мне, почему бы не использовать ViewModels?   -  person Zun    schedule 19.04.2019


Ответы (1)


Вам следует избегать передачи всего объекта с большим объемом данных в следующую активность. Таким образом, возможно, что ваш объект может иметь много данных. Поэтому иногда система не может обрабатывать много данных для передачи за раз. Попробуйте использовать Preferences для хранения данных вашего объекта и получения их в другом действии.

Пожалуйста, мой ответ здесь: Исключение при запуске активности android.os.TransactionTooLargeException: размер пакета данных

person Ajay Mehta    schedule 19.04.2019
comment
спасибо за предложение, но SharedPreferences здесь не вариант. - person lannyf; 19.04.2019