Android - 更改ImageView drawable消耗的内存太多

时间:2016-01-16 11:06:18

标签: android image android-imageview android-image

在我的Android应用中,我有一个自定义的ImageView,它基于用户交互,需要更新其图像。 ImageView只能有两张图像,分别代表卡片的背面和正面。 因此,当用户点击按钮时,我需要显示卡的背面(将我的自定义ImageView图像设置到卡的背面,当用户再次按下按钮时,将前图像设置为ImageView可绘制)。

为了实现这一点,我在自定义ImageView中有两种方法:

public void showBack() {
    setImageResource(R.drawable.card_back);
}

public void showFront() {
    setImageResource(R.drawable.card_front);
}

当然,这很好用,但我的应用程序的内存消耗有时会接近114 MB,并且随着用户点击按钮(旋转卡)而增加。

由于这个原因,我认为问题可能是由于图像的变化而产生的。 图像很小,一个是104.6KB,另一个是80.4KB(PNG格式),所以我不明白为什么我的应用程序消耗了这么多内存(可能因为图像分配很多次并且从未回收过?,或者可能是因为Android的drawables缓存系统?)

那么,我该怎么做才能解决我的问题?

谢谢。

图片尺寸为335 x 501

3 个答案:

答案 0 :(得分:1)

所以这里有一些因素可以发挥作用。 imageView维度(我假设)已在dp中定义。根据屏幕分辨率,这会转换为从手机到手机的像素数。因此,相同的drawable,当连接到不同手机中的imageView时,必须缩放以匹配px中显示它所需的imageView

此扩展需要大量内存,这会导致OOM异常。有些手机有一个大的RAM,可以完成这个缩放而不会造成任何问题,而较旧的型号可能无法实现。

当您加载imageView时,原始图像将保留在内存中,然后重新调整。我建议获取imageView的像素尺寸,然后相应地缩放图像,以产生最佳拟合。这将减少内存消耗。

This answerthis应该可以帮助您获取imageView的尺寸。

Bitmap icon = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon_resource);

     private Bitmap ScaleImage(Bitmap bitmap){
        //the original dimension of the bitmap
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int requiredWidth=0;
        int requiredHeight=0;
        //todo: Calculate the required dimensions of the bitmap as per the imageView

        ExifInterface exif;
        Matrix matrix = new Matrix();
        /* In case you need to rotate the bitmap
        try {
            exif = new ExifInterface(value);
            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
            Log.d("EXIF", "Exif: " + orientation);
            if (orientation == 6) {
                matrix.postRotate(90);
                Log.d("EXIF", "Exif: " + orientation);
            } else if (orientation == 3) {
                matrix.postRotate(180);
                Log.d("EXIF", "Exif: " + orientation);
            } else if (orientation == 8) {
                matrix.postRotate(270);
                Log.d("EXIF", "Exif: " + orientation);}

        }catch (IOException e){e.printStackTrace();}
       */

        matrix.postScale(requiredWidth/originalWidth, requiredHeight/originalHeight);
        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,width, height, matrix, true);
        return resizedBitmap;
    }

最后

public void showFront() {
    Bitmap icon = BitmapFactory.decodeResource(context.getResources(),
    R.drawable.icon_resource);
    Bitmap scaledBitmap = ScaleImage(icon);
    setImageResource(scaledBitmap);
}

理想情况下,您希望将图像的缩放比例移至Async Task,以便不阻止主线程。 请告诉我这是否有效。

答案 1 :(得分:0)

图像的大小在这里不起作用。另一方面,尺寸确实如此。因此,如果您使用大尺寸的图像并在ImageView中使用较小的分辨率,那么这将是一个问题,您最终可能会遇到OOM(Out of Memory Exception)。

请参阅: http://developer.android.com/training/displaying-bitmaps/index.html

答案 2 :(得分:0)

根据我在加载图片时的个人经验,您应该始终使用毕加索库。它有助于解决所有内存问题,让您轻松扩展等。 this