如何在Android Q中将图像保存到相机文件夹?

如何在Android Q中将图像保存到相机文件夹?,android,android-10.0,Android,Android 10.0,我需要将图像保存到camera文件夹,但由于Android Q getExternalStoragePublicDirectory已被弃用,我采用了另一种方法。 我拥有的内容(此方法接收位图及其名称): 这对所有需要的操作系统版本都非常有效,但它看起来不准确,我想找到一种更常见的方法。 我试着玩弄内容价值观,或者尝试一些类似于Q的方法,但是没有用。我在这里看到了很多问题,但它们都不能帮助我 问题是如何优化低于Q的操作系统的存储?我能编写的最通用的版本是: private Uri saveImag

我需要将图像保存到camera文件夹,但由于Android Q getExternalStoragePublicDirectory已被弃用,我采用了另一种方法。 我拥有的内容(此方法接收位图及其名称):

这对所有需要的操作系统版本都非常有效,但它看起来不准确,我想找到一种更常见的方法。 我试着玩弄内容价值观,或者尝试一些类似于Q的方法,但是没有用。我在这里看到了很多问题,但它们都不能帮助我


问题是如何优化低于Q的操作系统的存储?

我能编写的最通用的版本是:

private Uri saveImage(Context context, Bitmap bitmap, @NonNull String folderName, @NonNull String fileName) throws IOException {
    OutputStream fos = null;
    File imageFile = null;
    Uri imageUri = null;

    try {
        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, Environment.DIRECTORY_PICTURES + File.separator + folderName);
            imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);

            if (imageUri == null)
                throw new IOException("Failed to create new MediaStore record.");

            fos = resolver.openOutputStream(imageUri);
        } else {
            File imagesDir = new File(Environment.getExternalStoragePublicDirectory(
                    Environment.DIRECTORY_PICTURES).toString() + File.separator + folderName);

            if (!imagesDir.exists())
                imagesDir.mkdir();

            imageFile = new File(imagesDir, fileName + ".png");
            fos = new FileOutputStream(imageFile);
        }


        if (!bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos))
            throw new IOException("Failed to save bitmap.");
        fos.flush();
    } finally {
        if (fos != null)
            fos.close();
    }
    
    if (imageFile != null) {//pre Q
        MediaScannerConnection.scanFile(context, new String[]{imageFile.toString()}, null, null);
        imageUri = Uri.fromFile(imageFile);
    }
    return imageUri;
}
如果您找到了更好的方法,请在此处发布,我将其标记为答案。

使用此文档:

首先创建临时文件

从路径发送文件

将数据复制到存储器

MAIN_DIR:要在其中存储图像的主文件夹名称(如应用程序名称) IMAGE_DIR:要创建的子文件夹

扫描文件:(更多详细信息:)

fun扫描文件(上下文:上下文,路径:字符串){
MediaScannerConnection.scanFile(上下文,
arrayOf(path),null,
{newPath,uri->if(BuildConfig.DEBUG)
Log.e(“标记”、“完成扫描”+newPath)})
}

“但它看起来不准确”——我觉得没问题。在Q上,您可以在编写内容时使用
IS_PENDING
。“我如何优化低于Q的操作系统的保存?”--除了
fileHashCode
这对行之外,您的代码看起来是合理的。@Commonware,所以我可以用不同的方式保存它吗?没有办法像Q那样保存图像?我正在为insert寻找另一个URI,但什么也没有。“所以我可以用不同的方式保存它吗?”--当然可以。“没有办法像Q那样保存图像?”--没有办法保存在特定位置<代码>相对路径在Q之前不存在。请注意,
MediaStore
不会立即知道代码中早于Q的分支中的图像。如果这对您很重要,请使用
MediaScannerConnection.scanFile()
@pic:使用
Uri
,因为没有可使用的文件系统路径。Glide、Picasso和其他优秀的图像加载库可以显示由
MediaStore
Uri
标识的图像。或者,使用
ContentResolver
openInputStream()
自己读取图像字节。@pic:您需要查询
MediaStore
。如果您对此过程有疑问,并且找不到现有的答案,请询问另一个堆栈溢出问题。如何使用Environment.getExternalStorageDirectory()+“DCIM/”显示此映像+IMAGES\u FOLDER\u NAME bcz它在android 10中不起作用,你能解决这个问题吗
IMAGES\u FOLDER\u NAME
用于什么?是否需要自定义文件夹名?@RRGT19,可选文件夹名。我见过的最佳解决方案
private Uri saveImage(Context context, Bitmap bitmap, @NonNull String folderName, @NonNull String fileName) throws IOException {
    OutputStream fos = null;
    File imageFile = null;
    Uri imageUri = null;

    try {
        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, Environment.DIRECTORY_PICTURES + File.separator + folderName);
            imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);

            if (imageUri == null)
                throw new IOException("Failed to create new MediaStore record.");

            fos = resolver.openOutputStream(imageUri);
        } else {
            File imagesDir = new File(Environment.getExternalStoragePublicDirectory(
                    Environment.DIRECTORY_PICTURES).toString() + File.separator + folderName);

            if (!imagesDir.exists())
                imagesDir.mkdir();

            imageFile = new File(imagesDir, fileName + ".png");
            fos = new FileOutputStream(imageFile);
        }


        if (!bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos))
            throw new IOException("Failed to save bitmap.");
        fos.flush();
    } finally {
        if (fos != null)
            fos.close();
    }
    
    if (imageFile != null) {//pre Q
        MediaScannerConnection.scanFile(context, new String[]{imageFile.toString()}, null, null);
        imageUri = Uri.fromFile(imageFile);
    }
    return imageUri;
}
val mTempFileRandom = Random()

fun createTempFile(ext:String, context:Context):String {
  val path = File(context.getExternalCacheDir(), "AppFolderName")
  if (!path.exists() && !path.mkdirs())
  {
    path = context.getExternalCacheDir()
  }
  val result:File
  do
  {
    val value = Math.abs(mTempFileRandom.nextInt())
    result = File(path, "AppFolderName-" + value + "-" + ext)
  }
  while (result.exists())
  return result.getAbsolutePath()
}   
copyFileToDownloads(this@CameraNewActivity, File(savedUri.path))
    fun copyFileToDownloads(context: Context, downloadedFile: File): Uri? {

    // Create an image file name
    val timeStamp = SimpleDateFormat(DATE_FORMAT_SAVE_IMAGE).format(Date())
    val imageFileName = "JPEG_$timeStamp.jpg"
    val resolver = context.contentResolver

    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        val values = ContentValues().apply {
            put(MediaStore.Images.Media.DISPLAY_NAME, imageFileName)
            put(MediaStore.Images.Media.MIME_TYPE, IMAGE_MIME_TYPE)
            put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM + File.separator + MAIN_DIR + File.separator + IMAGE_DIR + File.separator)
        }

        resolver.run {
            val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)

            uri
        }
    } else {
        val authority = "${context.packageName}.provider"
        val imagePath =
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)?.absolutePath
        val destinyFile = File(imagePath, imageFileName)
        val uri = FileProvider.getUriForFile(context, authority, destinyFile)
        FileUtils.scanFile(context, destinyFile.absolutePath)

        uri
    }?.also { uri ->
        var writtenValue = 0L
        // Opening an outputstream with the Uri that we got
        resolver.openOutputStream(uri)?.use { outputStream ->
            downloadedFile.inputStream().use { inputStream ->
                writtenValue = inputStream.copyTo(outputStream)
                Log.d("Copy Written flag", " = $writtenValue")
            }
        }
    }
}
fun scanFile(context:Context, path:String) {
  MediaScannerConnection.scanFile(context,
                                  arrayOf<String>(path), null,
                                  { newPath, uri-> if (BuildConfig.DEBUG)
                                   Log.e("TAG", "Finished scanning " + newPath) })
}