Android 通过操作将图像从内部存储器保存到图库

Android 通过操作将图像从内部存储器保存到图库,android,kotlin,android-fileprovider,android-internal-storage,Android,Kotlin,Android Fileprovider,Android Internal Storage,我有一个聊天应用程序。如果用户发送图像,我会将该图像保存到应用程序的内部存储器中 data/data/package_name/.... 因此,如果用户单击该图像,我会向系统发送打开该图像的意图 val uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, File(it.localUri)) val intent = Intent(Intent.ACTION_VIEW).apply {

我有一个聊天应用程序。如果用户发送图像,我会将该图像保存到应用程序的内部存储器中

data/data/package_name/....
因此,如果用户单击该图像,我会向系统发送打开该图像的意图

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)
问题是,在图像查看器中,没有选择将文件保存在手机的公共存储器中,即在多媒体资料中。
有没有办法在不更改“我的应用”中图像的内部存储默认保存位置的情况下执行此操作?

如果您对此感兴趣,您可以使用
MediaStore
以编程方式将来自内部存储的图片保存到图库中

代码 你可以使用以下代码,我在我的应用程序中成功地使用了这些代码

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());       
}

文件
转换为
位图
和使用 <代码>媒体商店

笔记
  • BitmapFactory.decodeFile()
    需要运行时权限
    WRITE\u EXTERNAL\u STORAGE
  • 随着Android 10中作用域内存的引入(Android 11将强制使用,请参阅)
    MediaStore
    可能是将图片保存到多媒体资料中的唯一可靠方法
  • 范围存储的结果是,是的,您应该继续使用内部存储来缓存图片副本
测验 我使用
targetSdkVersion
29在以下设备/操作系统组合上测试了此代码

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

如果这是您感兴趣的内容,您可以使用
MediaStore
以编程方式将内部存储器中的图片保存到多媒体资料中

代码 你可以使用以下代码,我在我的应用程序中成功地使用了这些代码

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());       
}

文件
转换为
位图
和使用 <代码>媒体商店

笔记
  • BitmapFactory.decodeFile()
    需要运行时权限
    WRITE\u EXTERNAL\u STORAGE
  • 随着Android 10中作用域内存的引入(Android 11将强制使用,请参阅)
    MediaStore
    可能是将图片保存到多媒体资料中的唯一可靠方法
  • 范围存储的结果是,是的,您应该继续使用内部存储来缓存图片副本
测验 我使用
targetSdkVersion
29在以下设备/操作系统组合上测试了此代码

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

  • 这是一个非常好的答案。然而,我认为你不理解我的问题。在我的例子中,当我点击照片时,我不使用ImageViewer的自定义活动。相反,我用Android手机的默认图像查看器打开照片。那么我应该在哪里写上面的代码呢?@james04谢谢!我理解这一点,这就是为什么我说“如果这是你感兴趣的东西”。如果你能在聊天中的每张图片旁边放一个小按钮,那么我的答案可能会有用。不幸的是,如果您必须坚持使用默认的图像查看器,我就无法帮助您使用它。@james04 AFAIK,因为系统决定哪个应用程序将处理
    意图。ACTION\u VIEW
    (如果有更多,则允许您选择一个)您不能期望在每个平台上都有相同的行为。如果您想将图片保存到多媒体资料中,而不必使用wiewing,则可以使用
    Intent.ACTION\u MEDIA\u SCANNER\u SCAN\u FILE
    (Android Q中已弃用)。但我认为,没有任何
    Intent
    能够保证在所有平台上都能始终如一地执行这两种操作。这是一个非常好的答案。然而,我认为你不理解我的问题。在我的例子中,当我点击照片时,我不使用ImageViewer的自定义活动。相反,我用Android手机的默认图像查看器打开照片。那么我应该在哪里写上面的代码呢?@james04谢谢!我理解这一点,这就是为什么我说“如果这是你感兴趣的东西”。如果你能在聊天中的每张图片旁边放一个小按钮,那么我的答案可能会有用。不幸的是,如果您必须坚持使用默认的图像查看器,我就无法帮助您使用它。@james04 AFAIK,因为系统决定哪个应用程序将处理
    意图。ACTION\u VIEW
    (如果有更多,则允许您选择一个)您不能期望在每个平台上都有相同的行为。如果您想将图片保存到多媒体资料中,而不必使用wiewing,则可以使用
    Intent.ACTION\u MEDIA\u SCANNER\u SCAN\u FILE
    (Android Q中已弃用)。但我认为,没有任何
    Intent
    可以保证在所有平台上都能始终如一地执行这两种操作。