i am updating one bitmap in widget (the whole widget is only one ImageView) like this
remoteViews.setImageViewBitmap(...)
and in some rare situations (it happend 3 times in 6 months of every day use) i get "!!! FAILED BINDER TRANSACTION !!!". then, only phone reboot solves this problem. uninstaling and installing again, does not help, only reboot.
i checked the icon's size and it is only 56 kilobytes, so it fits within the IPC memory limit. when i remove setImageViewBitmap(...) the widget works again, but the bitmap is not updated. so the problem is in the bitmap itself. what could cause this binder transaction fail when the bitmal is this small?
for now, i solved this by saving the icon to /data and i am sending only the URI to widget. but i would like to know, where can be a problem, when i am clearly not hitting the IPC memory limit?
EDIT:
i forget to mention, it happend on android 2.3.5 and also 2.3.7
It seems we can not parse more then 1 mb in an intent.
The Binder transaction failed because it was too large.
During a remote procedure call, the arguments and the return value of the call are transferred as Parcel objects stored in the Binder transaction buffer. If the arguments or the return value are too large to fit in the transaction buffer, then the call will fail and TransactionTooLargeException
will be thrown.
The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process. Consequently this exception can be thrown when there are many transactions in progress even when most of the individual transactions are of moderate size.
There are two possible outcomes when a remote procedure call throws TransactionTooLargeException. Either the client was unable to send its request to the service (most likely if the arguments were too large to fit in the transaction buffer), or the service was unable to send its response back to the client (most likely if the return value was too large to fit in the transaction buffer). It is not possible to tell which of these outcomes actually occurred. The client should assume that a partial failure occurred.
The key to avoiding TransactionTooLargeException is to keep all transactions relatively small. Try to minimize the amount of memory needed to create a Parcel for the arguments and the return value of the remote procedure call. Avoid transferring huge arrays of strings or large bitmaps. If possible, try to break up big requests into smaller pieces.
If you are implementing a service, it may help to impose size or complexity contraints on the queries that clients can perform. For example, if the result set could become large, then don't allow the client to request more than a few records at a time. Alternately, instead of returning all of the available data all at once, return the essential information first and make the client ask for additional information later as needed.
This is caused because all the changes to the RemoteViews are serialised (e.g. setInt and setImageViewBitmap ). The bitmaps are also serialised into an internal bundle. Unfortunately this bundle has a very small size limit.
You can solve it by scaling down the image size this way:
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;
}
Choose newHeight to be small enough (~100 for every square it should take on the screen) and use it for your widget, and your problem will be solved :)
In case you were reusing your remoteViews variable: each time you update bitmap on the same ImageView
, this is recorded as separate remote views action. There is no way to clear or deduplicate list of actions, associated with RemoteViews
. The only thing you can do in this case is just recreate remoteVies instead of reusing it infinitely