小部件更新失败的活页夹事务

时间:2011-10-25 11:55:44

标签: android android-widget android-appwidget android-binder

我正在更新widget中的一个位图(整个小部件只有一个ImageView),就像这样

remoteViews.setImageViewBitmap(...)

并且在一些罕见的情况下(每天使用6个月内发生3次)我得到“!!! FAULED BINDER TRANSACTION !!!”。然后,只有手机重启解决了这个问题。卸载并再次安装,没有帮助,只能重新启动。

我检查了图标的大小,它只有56千字节,所以它符合IPC内存限制。当我删除setImageViewBitmap(...)时,窗口小部件再次工作,但位图未更新。所以问题出在位图本身。什么可能导致这个绑定器事务失败,当bitmal这么小?

现在,我通过将图标保存到/ data来解决这个问题,而我只将URI发送给widget。但我想知道,当我明显没有达到IPC内存限制时,哪里可能出现问题?

编辑: 我忘了提一下,它发生在android 2.3.5和2.3.7

3 个答案:

答案 0 :(得分:4)

似乎我们无法在意图中解析超过1 mb。

  

Binder交易失败,因为它太大了。   在远程过程调用期间,调用的参数和返回值将作为存储在Binder事务缓冲区中的Parcel对象传输。如果参数或返回值太大而无法放入事务缓冲区,则调用将失败并抛出TransactionTooLargeException

     

Binder事务缓冲区具有有限的固定大小,当前为1Mb,由进程正在进行的所有事务共享。因此,即使大多数单个事务的大小适中,当有许多事务正在进行时,也会抛出此异常。

     

当远程过程调用抛出TransactionTooLargeException时,有两种可能的结果。客户端无法将其请求发送到服务(很可能,如果参数太大而无法放入事务缓冲区中),或者服务无法将其响应发送回客户端(最有可能的话,如果返回值为太大而不适合事务缓冲区)。无法确定实际发生了哪些结果。客户应该假设发生了部分故障。

     

避免TransactionTooLargeException的关键是保持所有事务相对较小。尝试最小化为参数创建Parcel所需的内存量以及远程过程调用的返回值。避免传输大量字符串或大位图。如果可能的话,尝试将大量请求分解成更小的部分。

     

如果要实现服务,则可能有助于对客户端可以执行的查询施加大小或复杂性约束。例如,如果结果集可能变大,则不允许客户端一次请求多个记录。或者,不是一次性返回所有可用数据,而是首先返回基本信息,然后根据需要让客户端请求其他信息。

答案 1 :(得分:1)

这是因为对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)并将其用于您的小部件,您的问题将得到解决:)

答案 2 :(得分:1)

如果您正在重复使用您的remoteViews变量:每次更新同一ImageView上的位图时,都会将其记录为单独的远程视图操作。无法清除或删除与RemoteViews关联的操作列表。在这种情况下,你唯一能做的就是重新创建remoteVies,而不是无限地重复使用