简体   繁体   English

通过 ACTION_VIEW 意图将图像从内部存储保存到图库

[英]Save image from internal storage to gallery through ACTION_VIEW intent

I have a chat application.我有一个聊天应用程序。 If a user sends an image i save that image to internal storage of the app under如果用户发送图像,我将该图像保存到应用程序的内部存储下

data/data/package_name/....

So if the user clicks on that image i send an intent to the system to open it因此,如果用户单击该图像,我会向系统发送一个意图以打开它

val uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, File(it.localUri))
       val intent = Intent(Intent.ACTION_VIEW).apply {
       flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
       setDataAndType(uri, "image/*")
    }
    startActivity(intent)

The problem is that in the image viewer there is no choice to save the file in the public storage of the phone, in that case in the gallery.问题是,在图像查看器中,没有选择将文件保存在手机的公共存储中,在这种情况下是在图库中。 Is there any way to do that without changing the internal storage default save location of the images in my app?有没有办法在不更改我的应用程序中图像的内部存储默认保存位置的情况下做到这一点?

If this is something you are interested in, you can use MediaStore to programmatically save in the gallery a picture from your internal storage.如果您对此感兴趣,可以使用MediaStore以编程方式将内部存储中的图片保存在图库中。

Code代码

You could use the following code, which I successfully use in my app.您可以使用以下代码,我在我的应用程序中成功使用了该代码。

ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "MyPicture.jpg");
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
   contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
}

ContentResolver resolver = myContext.getContentResolver();
Bitmap bitmap;
Uri uri;
try {
   // Requires permission WRITE_EXTERNAL_STORAGE
   bitmap = BitmapFactory.decodeFile(currentPhotoPath);
   uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
} catch (Exception e) {
   Log.e(LOG_TAG, "Error inserting picture in MediaStore: " + e.getMessage());
   return;
}

try (OutputStream stream = resolver.openOutputStream(uri)) {
   if (!bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream) {
      throw new IOException("Error compressing the picture.");
   }
} catch (Exception e) {
   if (uri != null) {
      resolver.delete(uri, null, null);
   }
   Log.e(LOG_TAG, "Error adding picture to gallery: " + e.getMessage());       
}

Credits to this answer for the conversion of File to Bitmap and to this answer for the usage of MediaStore .学分这个答案对的转换FileBitmap这个答案的使用MediaStore

Notes笔记

  • BitmapFactory.decodeFile() requires the runtime permission WRITE_EXTERNAL_STORAGE BitmapFactory.decodeFile()需要运行时权限WRITE_EXTERNAL_STORAGE
  • With the introduction of scoped memory in Android 10 (which will become mandatory in Android 11, see this article ) MediaStore is probably the only reliable way to save pictures to the gallery随着在 Android 10 中引入作用域内存(这将在 Android 11 中成为强制性要求,请参阅本文MediaStore可能是将图片保存到图库的唯一可靠方法
  • A consequence of scoped storage is that, yes, you should keep using the internal storage for the cache copy of your picture.范围存储的结果是,是的,您应该继续使用内部存储来缓存图片的副本。

Tests测试

I have tested this code with with targetSdkVersion 29 on the following devices / OS combinations我已经在以下设备/操作系统组合上使用targetSdkVersion 29 测试了此代码

  • Samsung Galaxy S10 / API 29三星 Galaxy S10 / API 29
  • Samsung Galaxy S9 / API 29三星 Galaxy S9 / API 29
  • Huawei Nexus 6P / API 27华为 Nexus 6P / API 27

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM