Как предотвратить TransactionTooLargeException или восстановиться после него

Я отправляю данные через трансляции следующим образом:

Intent outIntent = new Intent(Const.ACTION_FEED);
outIntent.putExtra(Const.EXTRA_FEED, data);
sendBroadcast(outIntent);

Проблема в том, что data может стать довольно большим, что приведет к TransactionTooLargeException. В документации говорится:

Буфер транзакций Binder имеет ограниченный фиксированный размер, в настоящее время 1 МБ, который используется всеми транзакциями, выполняемыми для процесса. Следовательно, это исключение может быть вызвано, когда выполняется много транзакций, даже если большинство отдельных транзакций имеют умеренный размер.

Итог: кажется, невозможно заранее сказать, какой размер приемлем для data.

Более того:

Ключ к тому, чтобы избежать TransactionTooLargeException, заключается в том, чтобы все транзакции были относительно небольшими. [...] Если возможно, попробуйте разбить большие запросы на более мелкие части.

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

Логичным шагом было бы обернуть весь код в блок try/catch, а при получении исключения TransactionTooLarge разбить данные на более мелкие фрагменты и повторить попытку.

Увы, согласно logcat, исключение выбрасывается не на стороне вызывающей стороны, а в системном процессе. Затем система приводит к сбою получателя широковещательной рассылки, после чего любое восстановление выходит из-под контроля отправителя.

Как узнать, сколько данных можно отправить в качестве дополнительной рассылки, и предотвратить сбой получателя данных?


person user149408    schedule 19.07.2019    source источник
comment
Я отправляю данные через широковещательные рассылки — почему? Какое приложение будет принимать эту трансляцию? Как вы собираетесь запретить всем другим приложениям получать эту трансляцию? Как вы планируете решить проблему, что ваша трансляция не будет работать на Android 8.0+, так как там запрещены неявные трансляции?   -  person CommonsWare    schedule 20.07.2019
comment
Предполагая, что приемник находится в вашем приложении, вам, вероятно, лучше использовать шину событий или использовать rxjava в качестве шины событий. Если вы отправляете его чему-то за пределами вашего приложения, вам, вероятно, нужно отправить ему uri для данных и предоставить ContentProvider, который он может запрашивать с помощью этого uri для данных.   -  person Gabe Sechan    schedule 20.07.2019
comment
@CommonsWare Любое заинтересованное приложение может получать трансляцию, если у него есть разрешение на определение местоположения (поскольку единственная конфиденциальная информация в данных позволяет делать выводы о местоположении устройства). Это задумано как открытый интерфейс с несколькими отправителями и получателями, которые могут даже не знать друг о друге. Получатели должны зарегистрировать BroadcastReceiver во время выполнения, чтобы он мог принимать неявные широковещательные сообщения.   -  person user149408    schedule 20.07.2019
comment
Любое заинтересованное приложение может получать трансляцию, если у него есть разрешение на определение местоположения — вы ничего не делаете в этой трансляции, чтобы наложить такое ограничение, по крайней мере, на основе кода в вашем вопросе. Кроме того, я согласен с рекомендацией Гейба использовать что-то другое для массовой передачи данных, где ContentProvider является разумным выбором. В качестве бонуса вы можете защитить этого провайдера с разрешением ACCESS_FINE_LOCATION, заодно решив проблему с разрешениями, поскольку сама трансляция только с Uri не будет содержать личных данных.   -  person CommonsWare    schedule 20.07.2019
comment
@CommonsWare относительно ограничений, действительно, я не указал это в вопросе для простоты. Фактический код определяет разрешения для трансляции.   -  person user149408    schedule 20.07.2019