Android 6.0以上加载图片触发Canvas超大Bitmap绘制异常求助
Hey there, let's tackle this frustrating bitmap size issue you're hitting! The error message is crystal clear here: you're trying to draw a 144MB bitmap—that's way beyond what Android's system can handle, especially on newer versions (6.0+) where memory management is stricter than on Android 6.0. Let's break down why your current attempts might not be working, and what you can do to fix it.
Why Your Current Fixes Aren't Cutting It
- Switching image loaders (Glide/Fresco/Picasso): All these libraries handle bitmap loading, but they won't magically shrink your image unless you explicitly tell them to. Loading the full-size bitmap will trigger the same error no matter which library you use.
- Increasing heap memory in
AndroidManifest.xml: This is a band-aid at best. Newer Android versions limit how much heap memory apps can use, and a 144MB bitmap will still blow past those limits. - Bitmap compression (file-level): If you're using
Bitmap.compress()to reduce file size, that only affects the saved file—not the in-memory size of the bitmap. The full-size bitmap is still loaded into memory before compression, which is why you're still seeing the error.
Step-by-Step Solutions
Let's focus on reducing the in-memory size of the bitmap before it's loaded into memory—that's the key here.
1. Load Bitmaps to Match Your ImageView's Exact Size (For Glide)
If you're using Glide, make sure you're telling it to load the bitmap at the exact dimensions of your ImageView, not the full original size. This uses downsampling to reduce memory usage drastically:
Glide.with(context) .load(yourImageUrlOrPath) .override(imageView.getWidth(), imageView.getHeight()) // Match ImageView size .fitCenter() // Or centerCrop() depending on your layout needs .format(DecodeFormat.PREFER_RGB_565) // Use RGB_565 to cut memory in half .into(imageView);
RGB_565uses 2 bytes per pixel instead of 4 (ARGB_8888), which immediately halves the bitmap's memory footprint.- If you don't know the ImageView's size upfront (e.g., in a RecyclerView), use
fitCenter()/centerCrop()to let Glide handle downsampling automatically instead of loading the full original size.
2. Manual Downsampling for Local Images
If you're loading local images (from storage), calculate a sampling rate to load only the pixels you need:
// First, get the image's dimensions without loading it into memory BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(localImagePath, options); // Calculate the sampling rate to fit your ImageView int reqWidth = imageView.getWidth(); int reqHeight = imageView.getHeight(); int inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Now load the downsized bitmap options.inJustDecodeBounds = false; options.inPreferredConfig = Bitmap.Config.RGB_565; // Save memory options.inSampleSize = inSampleSize; Bitmap downsizedBitmap = BitmapFactory.decodeFile(localImagePath, options); // Set the bitmap to your ImageView imageView.setImageBitmap(downsizedBitmap);
Here's the calculateInSampleSize helper method:
private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Double the sample size until the downsized image fits the target dimensions while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
3. Check for Memory Leaks
Newer Android versions are stricter about memory leaks, so if bitmaps aren't being properly recycled, they can pile up and trigger this error. Use tools like LeakCanary to detect if your app is holding onto unused bitmaps or ImageViews.
4. Avoid Loading Super-Large Images Entirely
If your source images are massive (e.g., 4000x3000 pixels or bigger), consider resizing them on the server side (for network images) or before storing them locally. Loading such large images into memory is never a good idea, even on high-end devices.
Why This Works on Android 6.0 but Not Newer Versions
Android 6.0 (Marshmallow) has more relaxed memory limits compared to later versions (Nougat and above). The ART runtime in newer Android versions enforces stricter memory allocation rules, so a bitmap that just barely fits in 6.0 will trigger an error in 7.0+.
内容的提问来源于stack exchange,提问作者Romil Singh Tomar

