Android拍照存SQLite报错:Can't compress a recycled bitmap
Hey there, let's tackle this super frustrating issue you're facing—nothing's more annoying than chasing a recycled bitmap error when you can't spot where the recycle() call is happening! Let's break down the root cause and actionable fixes:
Core Issue Breakdown
This error pops up because the Bitmap object you're trying to compress with compress() has already been recycled (either via an explicit recycle() call in your code, or automatically by the Android system due to memory constraints). Once a bitmap is recycled, it's no longer usable for any operations like compression.
Step-by-Step Fixes & Debugging Tips
1. Stop Using the Original Camera Bitmap Directly
The thumbnail bitmap returned by data.getParcelableExtra("data") (from the camera intent) is often managed by the system, and might get recycled before you finish processing it. Instead, create a copy of the bitmap to work with:
Bitmap originalBitmap = data.getParcelableExtra("data"); if (originalBitmap != null && !originalBitmap.isRecycled()) { // Create a mutable copy to avoid relying on the system-managed bitmap Bitmap workingBitmap = originalBitmap.copy(originalBitmap.getConfig(), true); // Compress the copy into a byte array for SQLite ByteArrayOutputStream stream = new ByteArrayOutputStream(); workingBitmap.compress(Bitmap.CompressFormat.JPEG, 80, stream); byte[] imageBytes = stream.toByteArray(); // Save imageBytes to your SQLite database here // Clean up: recycle the copy first, then the original if (!workingBitmap.isRecycled()) workingBitmap.recycle(); if (!originalBitmap.isRecycled()) originalBitmap.recycle(); }
2. Fix Asynchronous Operation Timing
If you're using async tasks (Coroutines, AsyncTask, etc.) to handle SQLite inserts, you might be recycling the bitmap on the main thread before the async compression finishes.
- Always pass the bitmap copy (not the original) to your async task.
- Never recycle the bitmap until after the compression and database insert are fully complete.
3. Avoid Implicit System Recycling
Large camera photos are prime targets for system recycling when memory is low. Reduce memory pressure and prevent this:
- Load the full-size image from its file path (instead of using the camera's thumbnail) with downsampling to shrink it:
BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 4; // Shrink image to 1/4 its original size (adjust as needed) Bitmap downsampledBitmap = BitmapFactory.decodeFile(photoFile.getAbsolutePath(), options); - Convert the bitmap to a byte array immediately after loading, then recycle the bitmap right away—don't hold onto the bitmap object longer than necessary.
4. Check Third-Party Image Libraries
If you're using Glide, Picasso, or similar libraries to display the camera photo, these libraries automatically recycle bitmaps to save memory.
- Don't reuse the bitmap that the library loaded into an ImageView. Instead, reload the image directly from its source (file path or URI) to get a fresh bitmap for compression.
5. Track Down Hidden recycle() Calls
To find where the bitmap is being recycled:
- Add log statements everywhere you explicitly call
bitmap.recycle()to track when it happens. - Use Android Studio's Memory Profiler to monitor the bitmap's lifecycle—you can see exactly when it's marked for recycling.
- If you're using any custom view or utility class that handles bitmaps, double-check those for unintended
recycle()calls.
内容的提问来源于stack exchange,提问作者Werner

