Android,自定义View中的内存不足

时间:2011-01-27 14:05:50

标签: android image memory memory-management

我正在对一个应用程序进行压力测试,该应用程序由一系列自定义视图(实际上是3个)组成,这些视图保存在frameLayout中。

虽然一次只举行两次。我有视图1,添加视图2,动画1和2中的动画,然后删除1,反之亦然,如果我通过视图去除bacrd。

每个视图在使用以下方法创建时会加载大量图像数据:

mBmp[background] = BitmapFactory.decodeStream(context.getAssets().open("view1_background.png"));

下面是我的视图切换代码的​​示例,此切换到下一个视图。

currView.startAnimation(AnimClass.outToLeftAnimation(null));
    intView++;
    nextView = ViewFactory.getInstance(this, intView, viewInitializer);
    mainLayout.addView(nextView, 0);
    nextView.startAnimation(AnimClass.inFromRightAnimation(this));
    mainLayout.removeViewInLayout(currView);
    currView = nextView;
    nextView = null;

viewInitializer根据intView调用自定义视图并对其进行实例化,然后使用上述方法加载图像。

问题在于,如果我足够快地切换视图,我可以使它停止跟上(即使我在滑出动画完成之前禁用按钮)并且在几次切换之后我将失去大部分在视图中的图像,最后仍然有一个或两个最小的图像。除了以下消息(该视图中每个图像一个消息)之外,它不会显示任何错误:

01-27 13:52:00.730: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 139264
01-27 13:52:01.011: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 425984
01-27 13:52:01.011: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 1187840
01-27 13:52:01.011: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 139264
01-27 13:52:01.093: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 139264
01-27 13:52:01.128: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 425984
01-27 13:52:01.144: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 1187840
01-27 13:52:01.179: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 139264
01-27 13:52:01.245: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 425984
01-27 13:52:01.261: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 139264
01-27 13:52:01.277: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 1187840
01-27 13:52:01.343: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 139264
01-27 13:52:01.363: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 425984
01-27 13:52:01.409: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 1187840
01-27 13:52:01.429: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 139264
01-27 13:52:01.511: DEBUG/skia(23064): ------- imageref_ashmem create failed <(null)> 139264

如果我切换视图,它在每个视图上都是一样的。在我看来,我的视图切换代码不会在视图被删除时取消分配视图,或者在删除视图后图像(位图)不会被释放。

如果我然后使用意图返回我的主要活动,我会得到以下内容:

Surface  E  Surface (identity=4810) requestBuffer(0, 00000033) returneda buffer with a null handle
Surface  E  getBufferLocked(0, 00000033) failed (Out of memory)
Surface  E  dequeueBuffer failed (Out of memory)
ViewRoot  E  OutOfResourcesException locking surface
ViewRoot  E  android.view.Surface$OutOfResourcesException
ViewRoot  E     at android.view.Surface.lockCanvasNative(Native Method)
ViewRoot  E     at android.view.Surface.lockCanvas(Surface.java:314)
ViewRoot  E     at android.view.ViewRoot.draw(ViewRoot.java:1363)
ViewRoot  E     at android.view.ViewRoot.performTraversals(ViewRoot.java:1172)
ViewRoot  E     at android.view.ViewRoot.handleMessage(ViewRoot.java:1749)
ViewRoot  E     at android.os.Handler.dispatchMessage(Handler.java:99)
ViewRoot  E     at android.os.Looper.loop(Looper.java:123)
ViewRoot  E     at android.app.ActivityThread.main(ActivityThread.java:4627)
ViewRoot  E     at java.lang.reflect.Method.invokeNative(Native Method)
ViewRoot  E     at java.lang.reflect.Method.invoke(Method.java:521)
ViewRoot  E     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:871)
ViewRoot  E     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
ViewRoot  E     at dalvik.system.NativeStart.main(Native Method)

任何人都可以建议我可能出错的地方吗?

编辑:未找到确切原因,但我通过在切换视图之间执行垃圾收集来解决问题。

2 个答案:

答案 0 :(得分:0)

在使用大量图像时,我更喜欢某种“清理”...在从布局中删除视图之前,您是否尝试取消初始化(回收位图)您加载的图像?

答案 1 :(得分:0)

您是否考虑过使用位图选项导入占用较少图像数据的较小图像?如果您有高分辨率图像(例如相机照片),则无需向用户显示完整的图像分辨率。

在导入位图之前尝试执行此操作

Options options = new Options();            
options.inJustDecodeBounds = true;

BitmapFactory.decodeFile(context.getAssets().open("view1_background.png"), options);

options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

Log.i(getClass().getSimpleName(), 
            "height: " + options.outHeight +
            "\nwidth: " + options.outWidth +
            "\nmimetype: " + options.outMimeType +
            "\nsample size: " + options.inSampleSize);

options.inJustDecodeBounds = false;

mBmp[background] = BitmapFactory.decodeStream(context.getAssets().open("view1_background.png"));

样本大小由以下因素决定:

public static int calculateInSampleSize( 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;

    while (height / inSampleSize > reqHeight || width / inSampleSize > reqWidth) 
    {
        if (height > width)
        {
            inSampleSize = height / reqHeight;
            if (((double)height % (double)reqHeight) != 0) 
            {
                inSampleSize++;
            }
        } 
        else 
        {
            inSampleSize = width / reqWidth;
            if (((double)width % (double)reqWidth) != 0) 
            {
                inSampleSize++;
            }
        }
    }
    return inSampleSize;
}