Android Studio Java实现创建文件夹并保存图片(适配4.4-13)
适配Android 4.4~13的图片保存解决方案
核心问题拆解
不同Android版本的存储机制差异是关键:
- 4.4~9:采用传统外部存储,需
WRITE_EXTERNAL_STORAGE权限,可直接在根目录创建自定义文件夹 - 10~13:分区存储(Scoped Storage)生效,默认无法直接在外部存储根目录创建自定义文件夹,需使用媒体存储API或存储访问框架(SAF),且保存后需确保媒体库更新以同步到图库
分版本实现步骤
1. Android 4.4~9 处理方式
- 权限配置:在Manifest中声明
WRITE_EXTERNAL_STORAGE权限,Android 6.0及以上版本需动态申请该权限。 - 创建oscfolder文件夹:直接在外部存储根目录创建目标文件夹,代码示例:
File rootDir = Environment.getExternalStorageDirectory(); File oscFolder = new File(rootDir, "oscfolder"); if (!oscFolder.exists()) { boolean isCreated = oscFolder.mkdirs(); // 可添加日志或Toast验证创建结果 }
- 保存后同步图库:图片保存完成后,发送广播通知媒体扫描器更新,避免图库无法识别:
MediaScannerConnection.scanFile(context, new String[]{savedImagePath}, new String[]{"image/jpeg"}, null);
2. Android 10~13 处理方式
方案一:用媒体存储API存到Pictures/oscfolder(推荐,无需用户授权)
Android 10+无法直接在根目录创建自定义文件夹,但可通过RELATIVE_PATH指定存储路径为Pictures/oscfolder,图库可直接识别:
ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, "edited_image.jpg"); values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // 指定相对路径,在Pictures目录下创建oscfolder values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/oscfolder"); } // 将图片信息插入媒体库 Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); if (uri != null) { try (OutputStream outputStream = context.getContentResolver().openOutputStream(uri)) { // 将编辑后的Bitmap写入输出流 editedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream); // Android 10+系统会自动同步媒体库,无需手动扫描 } catch (IOException e) { e.printStackTrace(); } }
保存后可在内部存储/Pictures/oscfolder找到文件,图库也会同步显示。
方案二:用SAF让用户授权创建根目录的oscfolder(适合必须在根目录的场景)
若需强制在外部存储根目录创建oscfolder,需通过存储访问框架请求用户手动授权:
Intent safIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); startActivityForResult(safIntent, 1001); // 1001为自定义请求码
在回调中处理授权与文件创建(Android 11+建议用registerForActivityResult替代onActivityResult):
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1001 && resultCode == RESULT_OK) { Uri treeUri = data.getData(); // 持久化权限,避免重启APP后失效 getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); // 创建oscfolder文件夹 DocumentFile rootDir = DocumentFile.fromTreeUri(this, treeUri); DocumentFile oscFolder = rootDir.createDirectory("oscfolder"); // 创建图片文件并写入数据 DocumentFile imageFile = oscFolder.createFile("image/jpeg", "edited_image.jpg"); try (OutputStream outputStream = getContentResolver().openOutputStream(imageFile.getUri())) { editedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream); } catch (IOException e) { e.printStackTrace(); } } }
3. 权限统一适配
- 4.4~5.1:仅需在Manifest中声明权限,无需动态申请
- 6.0~9:需动态申请
WRITE_EXTERNAL_STORAGE权限 - 10~12:使用媒体存储API时无需声明存储权限;使用SAF无需权限,但需用户手动授权
- 13:保存到公共目录(如Pictures/Download)时,读取图片需申请
READ_MEDIA_IMAGES权限,保存时无需额外权限
常见问题修复
内部存储看不到oscfolder:
- Android 10+采用媒体存储API时,文件夹位于
Pictures目录下而非根目录,需前往内部存储/Pictures查找 - Android 4.4~9版本若文件夹隐藏,可发送媒体扫描广播触发识别
- Android 10+采用媒体存储API时,文件夹位于
存到Download文件夹图库看不到:
- Android 10+系统可能不会自动扫描Download目录,需手动触发媒体库更新:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { getContentResolver().notifyChange(imageUri, null); } else { MediaScannerConnection.scanFile(this, new String[]{imagePath}, null, null); }
内容的提问来源于stack exchange,提问作者AfroDemoz
相关产品推荐
相关产品推荐

