Download many large thumbnail bitmaps - Android

I am working on a media player application and want to upload album art images for display in a ListView. Now it works great with images that I automatically download from last.fm, which are under 500x500 png. However, I recently added another panel to my application that allows you to view full-screen images, so I replaced some of my work with a large (1024x1024) png.

Now, when I browse through several high-resolution albums, I get 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? So that everything you need should be thumbnails, and I could make a duplicate function or argument to get full-size images to display full screen.

In addition, I display these bitmaps on ImageViews, which are small, from 150x150 to 200x200. Smaller images are smaller than larger ones. Is there a way to apply a zoom filter to smooth the image (possibly anti-aliasing)? I don’t want to cache a bunch of additional thumbnail files if I don’t need it because it makes managing cover images difficult (for now, you can simply dump new ones in the directory and they will be used automatically the next time they are loaded).

The full code is in http://github.org/CalcProgrammer1/CalcTunes , in src / com / calcprogrammer1 / calctunes / AlbumArtManager.java, although it doesn’t have much different function (which returns to checking last.fm if the image is missing )

+4
source share
4 answers

I use this private function to adjust the size I want for my thumbnails:

 //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; } 
+2
source
  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; } 

Adapted from http://developer.android.com/training/displaying-bitmaps/load-bitmap.html , but to use downloads from files, not resources. I added a thumbnail option as such:

  //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's answer looks pretty similar and a bit concise, might use this solution instead, but this page had some good information about it about BitmapFactory.

0
source

One way to do this is with the AQuery library .

This is a library that allows you to be lazy to download images from your local storage or URL. With support for things like caching and scaling.

Example for lazy loading a resource without scaling:

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

An example for lazy loading an image into a File object with zooming out:

  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 

Example download from a URL using local memory caching, local caching, and resizing.

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

This will start the asynchronous loading of the image in myImageUrl , resize it to a width of 250, and cache it in memory and storage. Then it will show the image in your yourImageView . Whenever the image myImageUrl was loaded and cached before, this line of code will load one of them into the cache in memory or in storage.

Typically, these methods will be called in the getView method of the list adapter.

For complete documentation on AQuery image download capabilities, you can check the documentation .

0
source

This is easy to do with 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); } })); 

You can also cache responses using the cache and cacheTimeout .

0
source

Source: https://habr.com/ru/post/1479212/


All Articles