android - MediaStore contentResolver.insert() 在拍照时创建副本而不是替换现有文件(Android Q : 29)

标签 android android-10.0

我正在尝试使用以下代码保存从相机拍摄的图像:

@RequiresApi(Build.VERSION_CODES.Q)
private fun setImageUri(): Uri {
    val resolver = contentResolver
    val contentValues = ContentValues().apply {
        put(MediaStore.MediaColumns.DISPLAY_NAME, "house2.jpg")
        put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
        put(MediaStore.MediaColumns.RELATIVE_PATH, "Pictures/OLArt")
    }

    imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)

    return imageUri!!
}

该功能第一次运行良好。但是当图像 (house2.jpg) 已经存在时,系统将创建另一个名为“house2 (1).jpg”、“house2 (2).jpg”等的文件(而不是替换旧文件)

enter image description here

我可以在 contentValues 中设置什么来强制解析器替换文件而不是创建它的副本吗?

下面是拍照 Intent 的代码。
 Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->

     takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, setImageUri()) //<- i paste in the imageUri here

     // Ensure that there's a camera activity to handle the intent
     takePictureIntent.resolveActivity(packageManager)?.also {

         startActivityForResult(takePictureIntent, 102)
     }
  }

最佳答案

@CommonsWare 的评论有所帮助。

这个想法是

  • 使用resolver.query() 查询文件是否已经存在
  • 如果是,则从光标
  • 中提取 contentUri
  • 否则,使用 resolver.insert()

  • 创建查询选择时要注意的一件事是 MediaStore.MediaColumns.RELATIVE_PATH 需要终止“/”

    即 'Pictures/OLArt/' << 注意 OLArt/之后的斜线
        val selection = "${MediaStore.MediaColumns.RELATIVE_PATH}='Pictures/OLArt/' AND " 
                       + "${MediaStore.MediaColumns.DISPLAY_NAME}='house2.jpg' "
    

    以下是更新后的代码。
    @RequiresApi(Build.VERSION_CODES.Q)
    private fun getExistingImageUriOrNullQ(): Uri? {
        val projection = arrayOf(
            MediaStore.MediaColumns._ID,
            MediaStore.MediaColumns.DISPLAY_NAME,   // unused (for verification use only)
            MediaStore.MediaColumns.RELATIVE_PATH,  // unused (for verification use only)
            MediaStore.MediaColumns.DATE_MODIFIED   //used to set signature for Glide
        )
    
        // take note of the / after OLArt
        val selection = "${MediaStore.MediaColumns.RELATIVE_PATH}='Pictures/OLArt/' AND " 
                      + "${MediaStore.MediaColumns.DISPLAY_NAME}='house2.jpg' "
    
        contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            projection, selection, null, null ).use { c ->
            if (c != null && c.count >= 1) {
    
                print("has cursor result")
                c.moveToFirst().let {
    
                    val id = c.getLong(c.getColumnIndexOrThrow(MediaStore.MediaColumns._ID) )
                    val displayName = c.getString(c.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME) )
                    val relativePath = c.getString(c.getColumnIndexOrThrow(MediaStore.MediaColumns.RELATIVE_PATH) )
                    lastModifiedDate = c.getLong(c.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_MODIFIED) )
    
                    imageUri = ContentUris.withAppendedId(   
                                 MediaStore.Images.Media.EXTERNAL_CONTENT_URI,  id)
    
                    print("image uri update $displayName $relativePath $imageUri ($lastModifiedDate)")
    
                    return imageUri
                }
            }
        }
        print("image not created yet")
        return null
    }
    

    然后我将此方法添加到我现有的代码中
    @RequiresApi(Build.VERSION_CODES.Q)
    private fun setImageUriQ(): Uri {
    
        val resolver = contentResolver
    
        imageUri = getExistingImageUriOrNullQ() //try to retrieve existing uri (if any)
        if (imageUri == null) {
    
           //=========================
           // existing codes for resolver.insert
           //(SNIPPED)
           //=========================
        }
        return imageUri!!
    }
    

    关于android - MediaStore contentResolver.insert() 在拍照时创建副本而不是替换现有文件(Android Q : 29),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60632273/

    相关文章:

    java - 如何从图库中的图像中获取(提取)文本并搜索该文本 - Android?

    android - 写入权限不起作用 - 范围存储 Android SDK 30(又名 Android 11)

    android - android api 29 上的 adb remount 是否损坏?

    Android 10、API 29 更新后,Android 振动应用程序不再工作

    java - 如何检查 WiFi 扫描限制是否启用或禁用?

    java - 使用 achartengine 的日期和时间标签

    android - 从代码而非 xml 创建选择器时出现意外结果

    java - Android成功构建了gradle但没有在模拟器上安装应用程序

    android - 导航后未附加回收站 View

    java - Android Q - 通过 NFC 启动隐私更改 Activity