Сделайте снимок и сохраните в галерее

#android #kotlin #camera #image-gallery #android-camera-intent

#Android #kotlin #камера #изображение-галерея #android-камера-намерение

Вопрос:

Я потратил часы на изучение этой проблемы, и я не нашел решения (в StackOverflow или иным образом). Мое приложение нацелено на API 30, а minSskVersion равна 29. Я следую этому руководству:https://developer.android.com/training/camera/photobasics

У меня есть кнопка в моей активности, которая открывает камеру, используя намерение:

 fun takePhoto() {
    Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
        takePictureIntent.resolveActivity(packageManager)?.also {
              startActivityForResult(takePictureIntent, CAMERA_REQUEST)
        }
    }
}
  

Но я также хочу сохранить изображение в галерее устройства. Итак, я изменил свой takePhoto() метод на:

 fun takePhoto() {
    Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
        takePictureIntent.resolveActivity(packageManager)?.also {
            val photoFile: File? = try {
                createImageFile()
            } catch (ex: IOException) {
                ex.printStackTrace()
                null
            }

            photoFile?.also {
                try {
                    val photoURI: Uri = FileProvider.getUriForFile(
                        this,
                        "net.filiperamos.photogrid.provider",
                        it
                    )

                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
                } catch (ex: IllegalArgumentException) {
                    Log.d(TAG, "Could not get file URI.")
                    ex.printStackTrace()
                }

                startActivityForResult(takePictureIntent, CAMERA_REQUEST)
            }
        }
    }
}
  

и добавлен createImageFile() метод:

 private fun createImageFile(): File {
    val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
    val filename = "image_$timeStamp"
    val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_PICTURES)

    return File.createTempFile(filename, ".jpg", storageDir).apply {
        currentPhotoPath = absolutePath // Save path for later use
    }
}
  

В моем манифесте есть разрешение на использование камеры и внешнюю запись:

 <uses-feature
    android:name="android.hardware.camera"
    android:required="false" />

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  

Я добавил независимый поставщик в тег приложения:

     <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
  

и я создал file_paths.xml :

 <?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-files-path
        name="my_images"
        path="Android/data/net.ramos.photos/files/Pictures/" />
</paths>
  

Когда я запускаю этот код на своем устройстве, я получаю исключение при запуске FileProvider.getUriForFile() :

 java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/net.ramos.photos/files/Pictures/image_20200823_1415398042919497737944663.jpg
  

И если я изменю свой file_paths.xml файл, заменив external-files-path на external-path , ошибка исчезнет, но изображение нигде не сохраняется.

Чего я не понимаю?

Комментарии:

1. «и я создал file_paths.xml :» — замените свое path значение просто Pictures/ . «ни одно изображение нигде не хранится» — как вы его ищете? Он не будет отображаться в MediaStore , поскольку изображения, хранящиеся в этом месте, больше не подлежат индексации. Приложения в стиле галереи вряд ли в результате получат изображение.

2. Спасибо, теперь ошибка исчезла. Но я хочу, чтобы фотографии, сделанные с помощью моего приложения, были доступны другим приложениям. Как я могу сделать его доступным у системного медиа-провайдера?

3. В течение следующего года или около того используйте android:requestLegacyExternalStorage="true" общедоступное местоположение и записывайте в него, например, в Pictures/ каталог верхнего уровня, а не в конкретное местоположение приложения, как вы используете сейчас. На данный момент, учитывая весь беспорядок в области хранения и ограничения на ACTION_IMAGE_CAPTURE , я понятия не имею, каким будет план для желаемой функции через год.

Ответ №1:

Добавьте следующую строку в свой файл манифеста в качестве атрибута тега ‘application’,

 android:requestLegacyExternalStorage="true"
  

это должно решить проблему, с которой вы столкнулись, и исключение должно исчезнуть.

Комментарии:

1. Это не сработало: если я сохраню, external-files-path я все равно увижу ошибку, и если я изменю ее на external-path , я не увижу ошибки, но я также не увижу сохраненное изображение. Хотя, похоже, согласно @CommonsWare, я ищу фотографию не в том месте…