4

I'm working on a media player app and wish to load album art images to display in a ListView. Right now it works fine with the images I'm auto-downloading from last.fm which are under 500x500 png's. However, I recently added another panel to my app that allows viewing full screen artwork so I've replaced some of my artworks with large (1024x1024) png's instead.

Now when I scroll over several albums with high res artwork, I get a java.lang.OutOfMemoryError on my BitmapFactory.

    static public Bitmap getAlbumArtFromCache(String artist, String album, Context c)
    {
    Bitmap artwork = null;
    File dirfile = new File(SourceListOperations.getAlbumArtPath(c));
    dirfile.mkdirs();
    String artfilepath = SourceListOperations.getAlbumArtPath(c) + File.separator + SourceListOperations.makeFilename(artist) + "_" + SourceListOperations.makeFilename(album) + ".png";
    File infile = new File(artfilepath);
    try
    {
        artwork = BitmapFactory.decodeFile(infile.getAbsolutePath());
    }catch(Exception e){}
    if(artwork == null)
    {
        try
        {
            artwork = BitmapFactory.decodeResource(c.getResources(), R.drawable.icon);
        }catch(Exception ex){}
    }
    return artwork;
    }

Is there anything I can add to limit the size of the resulting Bitmap object to say, 256x256? That's all the bigger the thumbnails need to be and I could make a duplicate function or an argument to fetch the full size artwork for displaying full screen.

Also, I'm displaying these Bitmaps on ImageViews that are small, around 150x150 to 200x200. The smaller images scale down nicer than the large ones do. Is there any way to apply a downscaling filter to smooth the image (anti-aliasing perhaps)? I don't want to cache a bunch of additional thumbnail files if I don't have to, because it would make managing the artwork images more difficult (currently you can just dump new ones in the directory and they will automatically be used next time they get loaded).

The full code is at http://github.org/CalcProgrammer1/CalcTunes, in src/com/calcprogrammer1/calctunes/AlbumArtManager.java, though there's not much different in the other function (which falls back to checking last.fm if the image is missing).

4

4 回答 4

2

我使用这个私有函数来设置我想要的缩略图大小:

//decodes image and scales it to reduce memory consumption
public static Bitmap getScaledBitmap(String path, int newSize) {
    File image = new File(path);

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    options.inInputShareable = true;
    options.inPurgeable = true;

    BitmapFactory.decodeFile(image.getPath(), options);
    if ((options.outWidth == -1) || (options.outHeight == -1))
        return null;

    int originalSize = (options.outHeight > options.outWidth) ? options.outHeight
            : options.outWidth;

    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inSampleSize = originalSize / newSize;

    Bitmap scaledBitmap = BitmapFactory.decodeFile(image.getPath(), opts);

    return scaledBitmap;     
}
于 2013-05-05T06:04:13.513 回答
0

这很容易用droidQuery完成:

final ImageView image = (ImageView) findViewById(R.id.myImage);
$.ajax(new AjaxOptions(url).type("GET")
                           .dataType("image")
                           .imageHeight(256)//set the output height
                           .imageWidth(256)//set the output width
                           .context(this)
                           .success(new Function() {
                               @Override
                               public void invoke($ droidQuery, Object... params) {
                                   $.with(image).val((Bitmap) params[0]);
                               }
                           })
                           .error(new Function() {
                               @Override
                               public void invoke($ droidQuery, Object... params) {
                                   droidQuery.toast("could not set image", Toast.LENGTH_SHORT);
                               }
                           }));

您还可以使用cachecacheTimeout方法缓存响应。

于 2013-07-17T03:32:25.933 回答
0
    public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight)
{
    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, options);

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

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(path, options);
}

public static 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;

    if (height > reqHeight || width > reqWidth) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
return inSampleSize;
}

改编自http://developer.android.com/training/displaying-bitmaps/load-bitmap.html但使用来自文件而不是资源的负载。我添加了一个缩略图选项,如下所示:

    //Checks cache for album art, if it is not found return default icon
static public Bitmap getAlbumArtFromCache(String artist, String album, Context c, boolean thumb)
{
    Bitmap artwork = null;
    File dirfile = new File(SourceListOperations.getAlbumArtPath(c));
    dirfile.mkdirs();
    String artfilepath = SourceListOperations.getAlbumArtPath(c) + File.separator + SourceListOperations.makeFilename(artist) + "_" + SourceListOperations.makeFilename(album) + ".png";
    File infile = new File(artfilepath);
    try
    {
        if(thumb)
        {
            artwork = decodeSampledBitmapFromFile(infile.getAbsolutePath(), 256, 256);
        }
        else
        {
            artwork = BitmapFactory.decodeFile(infile.getAbsolutePath());
        }

Yoann 的答案看起来非常相似,而且更简洁,可能会改用该解决方案,但该页面上有一些关于 BitmapFactory 的好信息。

于 2013-05-05T06:16:04.263 回答
0

一种方法是使用AQuery 库

这是一个允许您从本地存储或 url 延迟加载图像的库。支持缓存和缩减等功能。

延迟加载资源而不进行缩减的示例:

AQuery aq = new AQuery(mContext);
aq.id(yourImageView).image(R.drawable.myimage);

使用缩小比例在 File 对象中延迟加载图像的示例:

    InputStream ins = getResources().openRawResource(R.drawable.myImage);
    BufferedReader br = new BufferedReader(new InputStreamReader(ins));
    StringBuffer sb;
    String line;
    while((line = br.readLine()) != null){
        sb.append(line);
        }

    File f = new File(sb.toString());

    AQuery aq = new AQuery(mContext);
    aq.id(yourImageView).image(f,350); //Where 350 is the width to downscale to

示例如何从具有本地内存缓存、本地存储缓存和调整大小的 url 下载。

AQuery aq = new AQuery(mContext);
aq.id(yourImageView).image(myImageUrl, true, true, 250, 0, null);

这将在 开始异步下载图像myImageUrl,将其调整为 250 宽度并将其缓存在内存和存储中。然后它将在您的yourImageView. 每当myImageUrl之前下载并缓存的图像时,这行代码将加载缓存在内存或存储中的图像。

通常这些方法会在getView列表适配器的方法中调用。

有关 AQuery 图像加载功能的完整文档,您可以查看文档

于 2013-05-05T06:41:43.327 回答