以编程方式添加到 AnimationDrawable 的图像会泄漏内存

发布于 2024-12-08 09:53:45 字数 651 浏览 0 评论 0原文

我有一个带有大量动画的 Android 应用程序。

当我以编程方式创建动画(使用 AnimationDrawable)时,非 java 对象(如 DDMS 堆选项卡中所示)会随着我加载的每个新动画而增长,并且即使在我加载后也不会收缩。动画被发布。

我从我编写的包装器对象中只有一个对每个 AnimationDrawable 对象的引用,并且我通过重写 finalize 方法并确保它被调用来验证该对象是否已释放。

最终 android 停止加载图像并将“内存不足”错误打印到日志中。

有趣的是,这种情况仅发生在某些设备(摩托罗拉 Xoom、索尼 Experia)中,而不会发生在其他设备(例如 Galaxy S)中。

正如您从我给出的设备示例中看到的那样,这个问题不是特定的 Honeycomb 或 pre-Honeycomb。

我尝试过的一些事情:

  1. 在完成当前动画后在每个帧上调用回收,但这似乎没有帮助。
  2. 将 null 分配给 AnimationDrawble 对象
  3. 确保不存在与持有动画可绘制对象引用的类相关的静态变量
  4. 确保在注释掉 myAnimation.addFrame(...) 后问题消失

I have an android App with plenty of animations.

When I programmatically create animations (using AnimationDrawable) the non-java object (as appears in DDMS Heap tab) grows with every new animation I load and never shrinks back even after my animations get released.

I have only one reference to each AnimationDrawable object from a wrapper object I wrote and I verified this object gets released by overriding the finalize method and making sure it gets called.

Eventually android stops loading images and prints "out of memory" errors to the log.

The interesting thing is that this happens only in some devices (Motorola Xoom, Sony Experia) and not in others (such as the Galaxy S).

This problem is not specific Honeycomb or pre-Honeycomb as you can see from the device examples I gave.

Some of the things I tried:

  1. Calling recycle on each of the frames after I am done with the current animation but it doesn't seem to help.
  2. Assigning null to the AnimationDrawble object
  3. Making sure that there are no static variable related to the class holding the reference to the animation drawable
  4. Make sure the problem disappears once I comment out myAnimation.addFrame(...)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

迷你仙 2024-12-15 09:53:45

这不是一个确切的答案,而是一个有用的提示,可以帮助您找到确切的泄漏发生位置。在您期望回收内存后执行堆转储,看看为什么您认为应该死亡的对象仍然活着。

确保您获得了 Eclipse 的内存分析器工具。 (http://www.eclipse.org/mat/)

This isn't an exact answer, but rather a helpful hint to find where the exact leak is occurring. Perform a heap-dump after you expect your memory to be reclaimed and see why the objects you think should be dead are still alive.

Make sure you get the memory analyzer tool for eclipse. (http://www.eclipse.org/mat/)

不打扰别人 2024-12-15 09:53:45

可能有两个原因,第一个是在创建位图时,第二个是在将位图转换为 BitmapDrawable 时。正如我从您的评论 (new BitmapDrawable(currentFrameBitmap) 中看到的那样,现在此方法更好地使用 BitmapDrawable(getResources(),currentFrameBitmap) 没有资源引用,位图即使正确缩放,也可能无法正确渲染。要有效加载位图,您可以正确缩放它。

public class BitmapDecoderHelper {
private Context context;
public BitmapDecoderHelper(Context context){
    this.context = context;
}
public int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
Log.d("height reqheight width reqwidth", height+"//"+reqHeight+"//"+width+"///"+reqWidth);
if (height > reqHeight || width > reqWidth) {
    if (width > height) {
        inSampleSize = Math.round((float)height / (float)reqHeight);
    } else {
        inSampleSize = Math.round((float)width / (float)reqWidth);
    }
}
return inSampleSize;
}
public Bitmap decodeSampledBitmapFromResource(String filePath,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;

    BitmapFactory.decodeFile(filePath, options);
    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    Log.d("options sample size", options.inSampleSize+"///");
    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    // out of memory occured easily need to catch and test the things.
    return BitmapFactory.decodeFile(filePath, options);
}
public int getPixels(int dimensions){
    Resources r = context.getResources();
    int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dimensions, r.getDisplayMetrics());
    return px;
}
public String getFilePath(Uri selectedImage){
    String[] filePathColumn = {MediaStore.Images.Media.DATA};
    Cursor cursor = context.getContentResolver().query(selectedImage, filePathColumn, null, null, null);
    cursor.moveToFirst();
    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
    String filePath = cursor.getString(columnIndex);
    cursor.close();
    return filePath;
}

}

There could be two possible reason, first at the time of creating the bitmap and second when you are converting the bitmap into the BitmapDrawable. As i can see from your comment (new BitmapDrawable(currentFrameBitmap) now this method is depreciated better to use BitmapDrawable(getResources(),currentFrameBitmap) Without the Resources reference, the bitmap may not render properly, even when scaled correctly. To load bitmap efficiently you can scale it properly.

public class BitmapDecoderHelper {
private Context context;
public BitmapDecoderHelper(Context context){
    this.context = context;
}
public int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
Log.d("height reqheight width reqwidth", height+"//"+reqHeight+"//"+width+"///"+reqWidth);
if (height > reqHeight || width > reqWidth) {
    if (width > height) {
        inSampleSize = Math.round((float)height / (float)reqHeight);
    } else {
        inSampleSize = Math.round((float)width / (float)reqWidth);
    }
}
return inSampleSize;
}
public Bitmap decodeSampledBitmapFromResource(String filePath,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;

    BitmapFactory.decodeFile(filePath, options);
    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    Log.d("options sample size", options.inSampleSize+"///");
    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    // out of memory occured easily need to catch and test the things.
    return BitmapFactory.decodeFile(filePath, options);
}
public int getPixels(int dimensions){
    Resources r = context.getResources();
    int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dimensions, r.getDisplayMetrics());
    return px;
}
public String getFilePath(Uri selectedImage){
    String[] filePathColumn = {MediaStore.Images.Media.DATA};
    Cursor cursor = context.getContentResolver().query(selectedImage, filePathColumn, null, null, null);
    cursor.moveToFirst();
    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
    String filePath = cursor.getString(columnIndex);
    cursor.close();
    return filePath;
}

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文