从ImageView保存图片至相册时触发File Not Found Exception问题求助
解决ImageView图片保存到相册的File Not Found Exception问题
嘿,别担心,作为初学者遇到这种问题很正常,我来帮你一步步搞定这个File Not Found Exception的问题!
为什么会出现这个错误?
你的代码在低版本Android上可能能跑,但在Android 6.0(API 23)及以上会因为权限问题报错,而Android 10(API 29)及以上还会因为存储策略变更导致直接操作外部目录被限制,最终触发文件找不到的异常。
一步步解决方法
1. 先添加必要的权限
首先在AndroidManifest.xml里添加存储权限:
<!-- 基础存储权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 13及以上需要额外的图片权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
2. 动态申请权限(API 23+必须)
从Android 6.0开始,危险权限需要在运行时申请,不能只靠Manifest。在你的MainActivity里添加以下代码:
private static final int REQUEST_STORAGE_PERMISSION = 100; // 检查并申请存储权限 private boolean checkStoragePermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { return true; } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE_PERMISSION); return false; } } // 低版本默认有权限 return true; } // 处理权限申请结果 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_STORAGE_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限通过,执行保存操作 saveImageToGallery(); } else { Toast.makeText(this, "需要存储权限才能保存图片哦", Toast.LENGTH_SHORT).show(); } } }
3. 适配不同Android版本的保存逻辑
Android 10及以上引入了Scoped Storage,不能直接写入外部存储的自定义目录,我们需要用MediaStore来插入图片;低版本则可以继续用传统方式。替换你原来的保存代码为:
private void saveImageToGallery() { BitmapDrawable draw = (BitmapDrawable) mainImage.getDrawable(); Bitmap bitmap = draw.getBitmap(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // Android Q及以上:用MediaStore保存 ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, System.currentTimeMillis() + ".jpg"); values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); // 保存到系统图片目录下的MyFolder文件夹 values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/MyFolder"); Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); if (uri != null) { try { OutputStream outputStream = getContentResolver().openOutputStream(uri); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); if (outputStream != null) { outputStream.close(); Toast.makeText(this, "图片保存成功啦!", Toast.LENGTH_SHORT).show(); } } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "保存失败:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } } } else { // Android Q以下:传统文件保存方式 File pictureDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); File myFolder = new File(pictureDir.getAbsolutePath() + "/MyFolder"); // 创建文件夹(如果不存在) if (!myFolder.exists()) { myFolder.mkdirs(); } String fileName = String.format("%d.jpg", System.currentTimeMillis()); File outFile = new File(myFolder, fileName); try { FileOutputStream outStream = new FileOutputStream(outFile); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream); outStream.flush(); outStream.close(); // 通知相册扫描新图片 Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(Uri.fromFile(outFile)); sendBroadcast(intent); Toast.makeText(this, "图片保存成功啦!", Toast.LENGTH_SHORT).show(); } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "保存失败:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } } }
4. 修改你的点击事件
把原来的点击事件改成先检查权限,再执行保存:
save.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v){ if (checkStoragePermission()) { saveImageToGallery(); } } });
关键注意点
- 权限是核心:如果没申请动态权限,App没有写入存储的权限,就会触发File Not Found Exception。
- 适配Scoped Storage:Android 10+不能直接写外部根目录,用
MediaStore是官方推荐的方式,也能确保图片被相册正确识别。 - 用系统目录:
Environment.DIRECTORY_PICTURES是系统默认的图片存储目录,比直接写根目录更安全,也符合系统规范。
现在你可以测试一下,应该就能正常保存图片到相册啦!
内容的提问来源于stack exchange,提问作者Muhammad Ramzan
相关产品推荐
相关产品推荐

