MediaStore contentResolver.insert () создает копии вместо замены существующего файла при съемке фотографий (Android Q: 29) - PullRequest
0 голосов
/ 11 марта 2020

Я пытаюсь сохранить изображение, снятое с камеры, используя следующие коды:

@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, et c (вместо замены старого файла)

enter image description here

Есть ли что-то, что я могу установить в contentValues, чтобы заставить преобразователь заменить файл, а не создавать его копии?

ниже это коды для цели фотосъемки.

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

Ответы [ 3 ]

1 голос
/ 11 марта 2020

Это правильное ожидаемое поведение. Причина, по которой вы видите разные постфиксы нумерации, заключается в том, что, вероятно, вы сохраняете файлы в одной и той же папке, поэтому Android необходимо создать уникальное имя, чтобы файлы могли существовать в одном месте.

Метод Insert предназначен для создания всегда новых записей. Возвращаемый Uri всегда является вновь вставленной записью. Но если файл сохраняется в папке, где уже есть другой файл с таким же именем, то в качестве такого имени файла должно быть другое Android добавит значение цифры c.

Если вы wi sh для замены существующей записи, затем вы должны сначала найти ее Uri, а затем использовать его, вызвав вместо этого метод ContentResolver update .

Если вы сохраняете фотографии из приложения камеры, затем вместо имени можно использовать текущее время, включая миллисекунды, чтобы обеспечить уникальность.

0 голосов
/ 12 марта 2020

@ Комментарий CommonsWare помог.

Идея состоит в том, чтобы

  1. Запросить, если файл уже существует с resolver.query ()
  2. Если да, извлеките contentUri из курсора
  3. В противном случае используйте resolver.insert ()

. При создании выбора для запроса следует обратить внимание на то, что MediaStore.MediaColumns.RELATIVE_PATH требует завершения "/"

т.е. / OLArt / '<< note the sla sh после OLArt / </p>

    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!!
}
0 голосов
/ 11 марта 2020

Вы пытались использовать метод update ?

Проверьте, не создает ли он новый, когда ничего еще нет, если он не работает, тогда используйте insert или update в зависимости от того, файл создан.

...