简体   繁体   English

在Android中的列表视图中显示和滚动大位图时出现异常

[英]Exception while displaying and scrolling large bitmaps in list view in Android

I am facing this issue but unable to resolve. 我正面临这个问题,但无法解决。 My problem goes like this: 我的问题是这样的:

  • I have a list view. 我有一个列表视图。 My list row contains an image view and one text view 我的列表行包含图像视图和一个文本视图
  • I have 20 images each of 12 MB size stored in my SD card 我有20张图像,每张图像都存储在SD卡中,每张12 MB
  • I have to set these images in imageView of my list view 我必须在列表视图的imageView中设置这些图像

I am able to do it by following code. 我可以通过以下代码来完成它。 This I am doing in getView method of my custom adapter: 这是我在我的自定义适配器的getView方法中做的:

public View getView (int position, View convertView, ViewGroup parent) {
    //other stuffs like recycling, view holder etc...
    BitmapFactory.Options opt = new BitmapFactory.Options();
    opt.inSampleSize = 4; // tried with 8,12 too
    Bitmap bitmap = BitmapFactory.decodeFile(imageUri, opt);
    holder.imageView.setImageBitmap(bitmap);
    return convertView;
}

Now this code works fine with small images but plays havoc for image of large size. 现在这个代码可以很好地处理小图像,但对大尺寸图像会造成严重破坏。 Application crashes with OutOfMemoryError . 应用程序与OutOfMemoryError崩溃。 If I try to increase inSampleSize to 8 or 12, it works but image quality drastically comes down and image doesn't look original image at all. 如果我尝试将inSampleSize增加到8或12,它会起作用,但图像质量会大幅降低,图像看起来根本不会显示原始图像。 I tried with imageView.setImageURI(imageUri) also but documentation suggests to use setImageBitmap only. 我也尝试使用imageView.setImageURI(imageUri)但文档建议仅使用setImageBitmap

Now please someone help me to rectify this issue. 现在请有人帮我纠正这个问题。 How can I resolve this without compromising with image quality? 如何在不影响图像质量的情况下解决此问题?

A quick band-aid that might help would be to use: 一个快速的创可贴可能有助于使用:

opt.inPreferredConfig = Bitmap.Config.RGB_565;

That will load your images without an alpha channel, and only using 2 bytes per pixel (rather than 4 bytes with the default ARGB_8888). 这将加载没有alpha通道的图像,并且每个像素仅使用2个字节(而不是使用默认ARGB_8888的4个字节)。

Depending on the length of your list, you might have to load/unload your images as they become visible on screen/leave the screen. 根据列表的长度,您可能必须加载/卸载图像,因为它们在屏幕上可见/离开屏幕。

Try setting inSampleSize to 2 or 4, and scale width and height down using the Matrix class. 尝试将inSampleSize设置为2或4,并使用Matrix类缩放宽度和高度。 But as you said in another answer, this may hit performance. 但正如你在另一个答案中所说,这可能会影响表现。

float desiredWidth = 60; // the width you want your icon/image to be
float scale = desiredWidth/actualWidth // bitmap.getWidth() for actualWidth
// float scale = desiredHeight/actualHeight // If you want to go by a particular height

Matrix matrix = new Matrix();
matrix.setScale(scale, scale);

holder.imageView.setImageBitmap(Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false));
bitmap.recycle(); // ish

Second option. 第二种选择。 Before instantiating the Adapter class, get a Cursor object to thumbnail images and pass the cursor into the constructor of the adapter, making it a class varaible. 在实例化Adapter类之前,获取缩放图像的Cursor对象,并将光标传递给适配器的构造函数,使其成为可变类。 Use the same cursor on every view row in the ListView. 在ListView中的每个视图行上使用相同的光标。

Uri tUri = MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI; // Where thumbnails are stored
String[] columns = { MediaStore.Images.ImageColumns._ID,  MediaStore.Images.ImageColumns.DATE_TAKEN, MediaStore.Images.ImageColumns.DISPLAY_NAME};

Cursor thumbCursor = this.managedQuery(tUri, null, null, null, null); // May want to use more paramaters to filter results
cursor.moveToFirst();

.... instantiate adapter, pass in cursor ....

public View getView (int position, View convertView, ViewGroup parent) {

int columnIndex = cursor.getColumnIndex(MediaStore.Images.Thumbnails.DATA);
String filePath = cursor.getString(columnIndex);
Bitmap bitmap = BitmapFactory.decodeFile(filePath);
holder.imageView.setImageBitmap(bitmap);
cur.moveToNext();
// BitmapDrawable d = new BitmapDrawable(listActivity.getResources(), filePath);
// holder.imageView.setImageDrawable(d);
}

Something like that. 这样的事情。 I did it in a hurry. 我匆忙做了。 Good luck =) 祝你好运=)

尝试根据图像尺寸计算比例因子,并调用Bitmap.recycle()来释放分配的内存

First of all, as images are of 12mb(even if they are of only 1mb), you have to scale them and downsize them to the dimensions of your imageview . 首先,因为图像是12mb(即使它们只有1mb),你必须缩放它们并将它们缩小到你的imageview的尺寸。

while you can also check for outofmemory exception ... 你还可以查看outofmemory exception ......

public View getView (int position, View convertView, ViewGroup parent) 
{
//other stuffs like recycling, view holder etc...

    boolean OOME = true;
    int sample = 4;

    while(OOME)
    {
        try
        {
            BitmapFactory.Options opt = new BitmapFactory.Options();
            opt.inSampleSize = sample; // tried with 8,12 too
            Bitmap bitmap = BitmapFactory.decodeFile(imageUri, opt);
            bitmap = bitmap.createScaledBitmap(bitmap,newWidth,newHeight,true);
            holder.imageView.setImageBitmap(bitmap);
            OOME = false;
        }
        catch(OutOfMemoryError e)
        {
            sample *= 2;
        }
    }
    return convertView;
}

I also take assumption, you are doing all the decoding stuff in a background thread to make your listview scroll smooth... 我也假设,你在background thread中做所有解码的东西 ,使你的listview scroll顺利...

While having many problems with Bitmaps and ListView , this was the best approach i can come with... still I am open for any changes or modifications or enhancments ... 虽然有很多问题BitmapsListView ,这是最好的方法,我可以跟...还是我打开任何变更修改,enhancments ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM