web-dev-qa-db-fra.com

Android Q: Obtenir une image de la galerie et la traiter

Je sais que cela semble être une question très basique, mais c'est spécifiquement pour Android Q.

Je veux juste obtenir une image de la galerie, la compresser et l'envoyer au serveur. Mais à cause du Android stockage étendu de Q, c'est plus difficile que je ne le pensais. Je vais d'abord expliquer ce que j'ai fait avec le code:

J'envoie d'abord l'intention de choisir l'image.

fun openGallery(fragment: Fragment){
    val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
    intent.type = "*/*"
    val mimeTypes = arrayOf("image/*")
    intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
    fragment.startActivityForResult(intent, REQUEST_IMAGE_PICK)
}

Cela fonctionne très bien, et je suis capable d'obtenir l'image dans la méthode onActivityResult

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

    if (requestCode == REQUEST_IMAGE_PICK && resultCode == Activity.RESULT_OK && null != data) {
        val selectedImage = data.data

        val source = ImageDecoder.createSource(activity!!.contentResolver, selectedImage)
        val bitmap = ImageDecoder.decodeBitmap(source)
        mBinding.circularProfileImage.setImageBitmap(bitmap)
    }
}

Bon maintenant, la question est de savoir comment puis-je accéder à cette image au format fichier, afin de pouvoir la traiter/compresser davantage.

Voici ce que j'ai essayé:

val mImagePath = getImagePathFromUri(activity!!, selectedImage)

Voici le chemin que j'ai:

/storage/emulated/0/DCIM/Camera/IMG_20191022_152437.jpg

J'en ai créé un fichier, de la manière suivante:

val file = File(mImagePath)

Et voici ma logique personnalisée pour compresser et télécharger l'image:

val mNewFile = MediaCompressor.compressCapturedImage(activity!!, file, "ProfilePictures")
uploadProfile(mNewFile)

Dans cette logique personnalisée, j'ai une méthode pour gérer l'échantillonnage et la rotation de l'image comme suit:

fun handleSamplingAndRotationBitmap(context: Context, selectedImage: File, reqWidth: Int, reqHeight: Int): Bitmap {

    val mUri = Uri.fromFile(selectedImage)

    // First decode with inJustDecodeBounds=true to check dimensions
    val options = BitmapFactory.Options()
    options.inJustDecodeBounds = true
    var imageStream = context.contentResolver.openInputStream(mUri)
    BitmapFactory.decodeStream(imageStream, null, options)
    imageStream!!.close()

    // Calculate inSampleSize
    options.inSampleSize =
        calculateInSampleSize(options, reqWidth, reqHeight)

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false
    imageStream = context.contentResolver.openInputStream(mUri)

    var img = BitmapFactory.decodeStream(imageStream, null, options)

    img = rotateImageIfRequired(context, img!!, mUri)
    return img
}

Mais lorsque j'essaie d'ouvrir le flux à l'aide de context.contentResolver.openInputStream j'obtiens l'erreur suivante:

Java.io.FileNotFoundException: /storage/emulated/0/DCIM/Camera/IMG_20191022_152437.jpg: open failed: EACCES (Permission denied)

Je sais que je reçois cela parce que dans Android 10, nous n'avons pas la permission d'accéder directement aux fichiers à partir du stockage externe.

Alors, veuillez m'aider à comprendre cela, comment puis-je utiliser l'image du stockage externe en tant que fichier dans Android 10.

Remarque: j'ai toutes les autorisations requises, ce n'est donc pas le problème

4
Parag Pawar

Je ne pense pas que ce soit une solution préférable, mais si vous voulez simplement avoir accès au stockage externe dans Android Q et plus, mettez ce code dans votre fichier manifeste:

<application
    Android:requestLegacyExternalStorage="true"
...
</application>

Gardez également à l'esprit qu'il ne s'agit que d'une solution temporaire et que cela ne fonctionnera pas éternellement, je recommanderais donc d'essayer différentes solutions.

0
schemabuoi