Сбой транзакции связывания при обновлении виджета - PullRequest
2 голосов
/ 25 октября 2011

Я обновляю одно растровое изображение в виджете (весь виджет - только один ImageView), как это

remoteViews.setImageViewBitmap(...)

и в некоторых редких ситуациях (это происходило 3 раза за 6 месяцев ежедневного использования), я получаю "!!! тогда только перезагрузка телефона решает эту проблему. удаление и установка снова, не помогает, только перезагрузка.

Я проверил размер значка, и он составляет всего 56 килобайт, поэтому он соответствует пределу памяти IPC. когда я удаляю setImageViewBitmap (...), виджет снова работает, но растровое изображение не обновляется. так что проблема в самом растровом изображении. что может привести к сбою этой транзакции связывания, когда битмал такой маленький?

на данный момент я решил эту проблему, сохранив значок в / data, и я отправляю только URI в виджет. но я хотел бы знать, где может быть проблема, когда я явно не достигаю предела памяти IPC?

EDIT: я забыл упомянуть, это произошло на Android 2.3.5, а также 2.3.7

Ответы [ 3 ]

4 голосов
/ 23 апреля 2012

Кажется, мы не можем проанализировать более 1 МБ в намерении.

Сбой транзакции Binder, поскольку она была слишком большой.Во время удаленного вызова процедуры аргументы и возвращаемое значение вызова передаются как объекты Parcel, хранящиеся в буфере транзакций Binder.Если аргументы или возвращаемое значение слишком велики для размещения в буфере транзакций, вызов завершится неудачно и будет выдан TransactionTooLargeException.

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

Возможны два результата, когда удаленный вызов процедуры вызывает исключение TransactionTooLargeException.Либо клиент не смог отправить свой запрос в службу (скорее всего, если аргументы были слишком велики для размещения в буфере транзакций), либо службе не удалось отправить свой ответ обратно клиенту (скорее всего, если возвращаемое значение былослишком большой для размещения в буфере транзакций).Невозможно сказать, какой из этих результатов действительно произошел.Клиент должен предположить, что произошел частичный сбой.

Ключом к исключению TransactionTooLargeException является сохранение относительно небольших транзакций.Постарайтесь минимизировать объем памяти, необходимый для создания Parcel для аргументов и возвращаемого значения удаленного вызова процедуры.Избегайте передачи огромных массивов строк или больших растровых изображений.Если возможно, попробуйте разбить большие запросы на более мелкие части.

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

1 голос
/ 16 октября 2015

В случае, если вы повторно использовали переменную remoteViews: каждый раз, когда вы обновляете растровое изображение на том же ImageView, это записывается как отдельное действие удаленного просмотра.Нет способа очистить или дедуплицировать список действий, связанных с RemoteViews.Единственное, что вы можете сделать в этом случае, это просто воссоздать remoteVies, а не использовать его бесконечно

1 голос
/ 31 декабря 2011

Это вызвано тем, что все изменения в RemoteViews сериализуются (например, setInt и setImageViewBitmap).Растровые изображения также сериализуются во внутренний пакет.К сожалению, этот пакет имеет очень маленький предел размера.

Вы можете решить эту проблему, уменьшив размер изображения следующим образом:

public static Bitmap scaleDownBitmap(Bitmap photo, int newHeight, Context context) {

final float densityMultiplier = context.getResources().getDisplayMetrics().density;        

int h= (int) (newHeight*densityMultiplier);
int w= (int) (h * photo.getWidth()/((double) photo.getHeight()));

photo=Bitmap.createScaledBitmap(photo, w, h, true);

return photo;
}

Выберите newHeight, чтобы быть достаточно маленьким (~ 100 для каждого квадратаэто должно взять на экране) и использовать его для вашего виджета, и ваша проблема будет решена:)

...