java - 为什么图像保存不再在 API 29 上工作
问题描述
在我的应用程序中,用户可以通过单击 DL 按钮将图片库中的图像保存到本地设备。
该代码确实适用于旧设备,但在 API 29 上它具有以下行为: 保存时我试图打开图库以查看发生了什么:图库得到更新,1 秒钟后出现空图像并立即消失。我注意到,图像已保存但没有出现,甚至在设备资源管理器中也没有。
//DEXTER HERE
Picasso.get().load(dummyimage.getLarge()).placeholder(R.drawable.ic_img_error).error(R.drawable.ic_red).into(saveImageToDirectory);
final Target saveImageToDirectory = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
ProgressDialog mydialog = new ProgressDialog(getActivity());
mydialog.setMessage("saving Image to phone");
mydialog.show();
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
try {
String fileName = "myApp_" + timeStamp + ".JPG";
String dirName= "/myApp";
File file = new File(requireActivity().getApplicationContext().getExternalFilesDir(null).getAbsolutePath() + dirName, fileName);
//new File(path for the file to be saved, saving file name)
if (!file.exists()) {
//check if the file already exist or if not create a new file
//if exist the file will be overwritten with the new image
File filedirectory = new File(requireActivity().getApplicationContext().getExternalFilesDir(null).getAbsolutePath() + dirName);
filedirectory.mkdirs();
}
if (file.exists()) {
file.delete();
}
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, ostream);
Toast.makeText(getActivity(), "Picture saved to Gallery" + file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
ostream.close();
mydialog.dismiss();
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "My Images");
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
values.put(MediaStore.MediaColumns.RELATIVE_PATH,"/myApp");
// API LEVEL Q: values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put("_data", file.getAbsolutePath());
ContentResolver cr = getActivity().getContentResolver();
cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} catch (Exception e) {
mydialog.dismiss();
Log.e("file creation error", e.toString());
}
}
@Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
如您所见,而不是
File filedirectory = new File(Environment.getExternalStorageDirectory() + dirName);
我已经在使用
File filedirectory = new File(requireActivity().getApplicationContext().getExternalFilesDir(null).getAbsolutePath() + dirName);
我希望这不应该是问题,但我有点坚持这种奇怪的行为。
这是我从 Logcat 中得到的错误:
E/文件创建错误:java.lang.IllegalArgumentException:主目录(无效)不允许用于内容://media/external/images/media;允许的目录是 [DCIM, Pictures]
PS:我使用 Dexter 来避免权限问题
解决方案
尝试这个
private Uri saveImage(Context context, Bitmap bitmap, @NonNull String folderName, @NonNull String fileName) throws IOException
{
OutputStream fos;
File imageFile = null;
Uri imageUri = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ContentResolver resolver = context.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM" + File.separator + folderName);
imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
fos = resolver.openOutputStream(imageUri);
} else {
String imagesDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM).toString() + File.separator + folderName;
imageFile = new File(imagesDir);
if (!imageFile.exists()) {
imageFile.mkdir();
}
imageFile = new File(imagesDir, fileName + ".png");
fos = new FileOutputStream(imageFile);
}
boolean saved = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
if (imageFile != null) // pre Q
{
MediaScannerConnection.scanFile(context, new String[]{imageFile.toString()}, null, null);
imageUri = Uri.fromFile(imageFile);
}
return imageUri;
}
并在您的清单文件中添加 requestLegacyExternalStorage
<application
android:allowBackup="true"
android:icon="@drawable/icon"
android:requestLegacyExternalStorage="true"
android:label="@string/app_name"
android:roundIcon="@drawable/icon"
android:supportsRtl="true"
android:theme="@style/AppTheme">
...
...
...
</application>
推荐阅读
- infinispan-9 - ISPN000373:尝试使用配置模板“XXXX”和 Infinispan 9.2.5 启动缓存
- angular - Angular Effects - 如何获得 100% 的测试结果(覆盖 funcs )?
- javascript - 为什么字符串中有加号?
- mysql - 什么存储合适
- node.js - 添加发布日期
- php - 在 ec2 AWS 上使用 mb_language PHP 发送电子邮件时出现错误 https 500
- c# - 安全漏洞:exe或其他恶意程序不得通过更改其标题和ext来上传pdf、doc、docx、xls、xlsx、jpg、jpeg、png等
- postgresql - postgres 在使用合并时是否使用索引?
- r - R - 使用 plot_ly() 自定义堆积条形图中标签的字体颜色
- javascript - 在mongodb中从开始日期和结束日期拆分所有日期