Android着色书onPause中PNG Bitmap保存不完整问题求助
问题分析
核心原因是PNG格式的压缩/写入耗时远高于JPEG:
- 按钮点击时Activity处于活跃状态,后台线程有足够时间完成PNG的完整写入;
- 但在
onPause中,Activity可能很快进入停止/销毁状态,后台线程还没完成PNG写入就被系统终止,导致文件损坏、仅保存部分内容。
另外,colourImageView.getmBitmap()返回的原Bitmap可能在Activity生命周期结束后被回收,进一步导致压缩数据不完整。
解决方案
方案1:使用WorkManager执行持久化后台保存(推荐)
WorkManager能保证任务即使在应用退出后也能完成,适合这种需要可靠持久化的场景:
- 添加WorkManager依赖(根据Gradle版本调整):
implementation "androidx.work:work-runtime:2.8.1"
- 创建自定义Worker类处理保存逻辑:
public class SaveBitmapWorker extends Worker { private static final String KEY_BITMAP_PATH = "bitmap_path"; public SaveBitmapWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @NonNull @Override public Result doWork() { String tempPath = getInputData().getString(KEY_BITMAP_PATH); if (tempPath == null) { return Result.failure(); } File tempFile = new File(tempPath); Bitmap bitmap = BitmapFactory.decodeFile(tempPath); if (bitmap == null) { tempFile.delete(); return Result.failure(); } File saveFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "savedBitmap1.png"); try (FileOutputStream fos = new FileOutputStream(saveFile)) { bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); SharedPreferencesFactory.saveString(getApplicationContext(), "savedBitmap1", saveFile.getPath()); tempFile.delete(); // 删除临时文件 bitmap.recycle(); return Result.success(); } catch (Exception e) { e.printStackTrace(); tempFile.delete(); return Result.retry(); } } public static OneTimeWorkRequest buildRequest(File tempBitmapFile) { Data inputData = new Data.Builder() .putString(KEY_BITMAP_PATH, tempBitmapFile.getAbsolutePath()) .build(); return new OneTimeWorkRequest.Builder(SaveBitmapWorker.class) .setInputData(inputData) .build(); } }
- 修改
setSavedBitmap方法,先把Bitmap保存到临时文件,再交给WorkManager:
private void setSavedBitmap(Bitmap finalBitmap) { File tempFile = new File(getCacheDir(), "temp_bitmap.png"); try (FileOutputStream fos = new FileOutputStream(tempFile)) { finalBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); OneTimeWorkRequest request = SaveBitmapWorker.buildRequest(tempFile); WorkManager.getInstance(this).enqueue(request); } catch (Exception e) { e.printStackTrace(); } }
方案2:复制Bitmap后再异步保存(简单临时方案)
通过复制Bitmap,避免原Bitmap被回收导致的写入异常,尽量降低线程被终止的影响:
private void setSavedBitmap(Bitmap finalBitmap) { Bitmap copiedBitmap = Bitmap.createBitmap(finalBitmap); File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "savedBitmap1.png"); new Thread(new Runnable() { public void run() { try (FileOutputStream fos = new FileOutputStream(file)) { copiedBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); SharedPreferencesFactory.saveString(getApplicationContext(), "savedBitmap1", file.getPath()); copiedBitmap.recycle(); } catch (Exception e) { e.printStackTrace(); copiedBitmap.recycle(); } } }).start(); }
注意:该方案仍存在线程被系统终止的风险,适合对可靠性要求不高的场景。
额外注意事项
- Android 10及以上可使用Scoped Storage,无需申请
WRITE_EXTERNAL_STORAGE权限;低版本需确保已申请该权限; - 禁止在
onPause中执行阻塞主线程的操作,避免ANR。
内容的提问来源于stack exchange,提问作者ttcreator
相关产品推荐
相关产品推荐

