【发布时间】:2020-04-02 17:59:33
【问题描述】:
Android Q 在存储管理方面发生了许多重大变化,我在应用程序中的一项功能是允许用户拍摄View 之类的CardView 项目,创建一个Bitmap并将其保存到设备的大容量存储中。保存完成后,它将触发Intent.ACTION_SEND,因此用户可以将最近保存的图像与一些描述分享到社交应用程序,并使用 GMail 撰写电子邮件。
这段代码 sn-p 工作正常。
try {
//Get primary storage status
String state = Environment.getExternalStorageState();
File filePath = new File(view.getContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) + "/" + "Shared");
if (Environment.MEDIA_MOUNTED.equals(state)) {
try {
if (filePath.mkdirs())
Log.d("Share Intent", "New folder is created.");
} catch (Exception e) {
e.printStackTrace();
Crashlytics.logException(e);
}
}
//Create a new file
File imageFile = new File(filePath, UUID.randomUUID().toString() + ".png");
//Create bitmap screen capture
Bitmap bitmap = Bitmap.createBitmap(loadBitmapFromView(view));
FileOutputStream outputStream = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
outputStream.flush();
outputStream.close();
Toast.makeText(view.getContext(), "Successfully save!", Toast.LENGTH_SHORT).show();
shareToInstant(description, imageFile, view);
} catch (IOException e) {
e.printStackTrace();
Crashlytics.logException(e);
}
但这会将图像文件保存到/storage/emulated/0/Android/data/YOUR_APP_PACKAGE_NAME/files/Pictures。
我想要的是像大多数应用程序一样将它们保存在根目录/storage/emulated/0/Pictures 的默认图片文件夹中,这样图像就更加暴露,并且可以通过 图库 轻松查看和扫描.
为了做到这一点,我将上面的代码 sn-p 更改为此。
//Create bitmap screen capture
Bitmap bitmap = Bitmap.createBitmap(loadBitmapFromView(view));
final String relativeLocation = Environment.DIRECTORY_PICTURES + "/" + view.getContext().getString(R.string.app_name);
final ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, UUID.randomUUID().toString() + ".png");
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);
final ContentResolver resolver = view.getContext().getContentResolver();
OutputStream stream = null;
Uri uri = null;
try {
final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
uri = resolver.insert(contentUri, contentValues);
if (uri == null || uri.getPath() == null) {
throw new IOException("Failed to create new MediaStore record.");
}
stream = resolver.openOutputStream(uri);
if (stream == null) {
throw new IOException("Failed to get output stream.");
}
if (!bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)) {
throw new IOException("Failed to save bitmap.");
}
//If we reach this part we're good to go
Intent mediaScannerIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File imageFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), contentValues.getAsString(MediaStore.MediaColumns.DISPLAY_NAME));
Uri fileContentUri = Uri.fromFile(imageFile);
mediaScannerIntent.setData(fileContentUri);
view.getContext().sendBroadcast(mediaScannerIntent);
shareToInstant(description, imageFile, view);
} catch (IOException e) {
if (uri != null) {
// Don't leave an orphan entry in the MediaStore
resolver.delete(uri, null, null);
}
e.printStackTrace();
Crashlytics.logException(e);
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
Crashlytics.logException(e);
}
}
}
同样有效,但无法将图像附加/共享到 GMail 等其他应用程序,据说 Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) 已被弃用,所以我想知道现在应该如何做,因为我已经为此尝试了大量研究但没有运气在这个问题上找到类似的场景。
这是我的 FileProvider 的样子。
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>
这是我用于 Intent 共享的 sn-p。
private static void shareToInstant(String content, File imageFile, View view) {
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("image/png");
sharingIntent.setType("text/plain");
sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
sharingIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
sharingIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(view.getContext(), BuildConfig.APPLICATION_ID + ".provider", imageFile));
sharingIntent.putExtra(Intent.EXTRA_TEXT, content);
try {
view.getContext().startActivity(Intent.createChooser(sharingIntent, "Share it Via"));
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(view.getContext(), R.string.unknown_error, Toast.LENGTH_SHORT).show();
}
}
【问题讨论】:
-
//If we reach this part we're good to go。是的,但您不必调用媒体扫描器。 -
shareToInstant(description, imageFile, view);否。使用 insert() 返回的 uri。将您的函数更改为shareToInstant(description, uri, view);。将 uri 用于 EXTRA_STREAM。 -
看到这个post。您可以在 Android Q 中使用
MediaStore和ContentResolver。使用Uri而不是路径 -
@blackapps 将图像保存在默认目录(例如图片)时,它是否自动可供图库和用户使用,因此不再需要通知媒体扫描仪?
标签: android mediastore android-fileprovider