180 votes

Environment.getExternalStorageDirectory() déprécié au niveau 29 de l'API java

Je travaille sur Android Java, j'ai récemment mis à jour le SDK au niveau 29 de l'API et un avertissement s'affiche, indiquant que

Environment.getExternalStorageDirectory() est déprécié au niveau 29 de l'API

Mon code est le suivant

private void saveImage() {

if (requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

    final String folderPath = Environment.getExternalStorageDirectory() + "/PhotoEditors";
    File folder = new File(folderPath);
    if (!folder.exists()) {
        File wallpaperDirectory = new File(folderPath);
        wallpaperDirectory.mkdirs();
    }

    showLoading("Saving...");
    final String filepath=folderPath
                + File.separator + ""
                + System.currentTimeMillis() + ".png";
    File file = new File(filepath);

    try {
        file.createNewFile();
        SaveSettings saveSettings = new SaveSettings.Builder()
                .setClearViewsEnabled(true)
                .setTransparencyEnabled(true)
                .build();
        if(isStoragePermissionGranted() ) {
            mPhotoEditor.saveAsFile(file.getAbsolutePath(), saveSettings, new PhotoEditor.OnSaveListener() {
            @Override
            public void onSuccess(@NonNull String imagePath) {
                hideLoading();
                showSnackbar("Image Saved Successfully");
                mPhotoEditorView.getSource().setImageURI(Uri.fromFile(new File(imagePath)));
                sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,Uri.fromFile(new File(filepath))));
                Intent intent = new Intent(EditImageActivity.this, StartActivity.class);
                startActivity(intent);
                finish();

            } 

            @Override
            public void onFailure(@NonNull Exception exception) {
                hideLoading();
                showSnackbar("Failed to save Image");
            }
       });
   }

Quelle sera l'alternative à cette situation ?

0 votes

Vérifier ma réponse ici stackoverflow.com/a/68110559/6039240

183voto

CommonsWare Points 402670

Utilice getExternalFilesDir() , getExternalCacheDir() ou getExternalMediaDirs() (méthodes sur Context ) au lieu de Environment.getExternalStorageDirectory() .

Ou bien, modifiez mPhotoEditor pour être en mesure de travailler avec un Uri alors :

  • Utilice ACTION_CREATE_DOCUMENT pour obtenir un Uri vers un lieu choisi par l'utilisateur, ou

  • Utilice MediaStore , ContentResolver y insert() pour obtenir un Uri pour un type de média particulier (par exemple, une image) - cf. cet exemple d'application qui montre comment procéder pour télécharger des vidéos MP4 à partir d'un site Web.

Notez également que votre Uri.fromFile con ACTION_MEDIA_SCANNER_SCAN_FILE devrait tomber en panne sous Android 7.0+ avec une FileUriExposedException . Sur Android Q, seul le MediaStore / insert() permettra à votre contenu d'être indexé par le MediaStore rapidement.

Notez que vous pouvez vous soustraire à ces changements de "stockage scopé" sous Android 10 et 11, si votre targetSdkVersion est inférieur à 30, en utilisant android:requestLegacyExternalStorage="true" dans le <application> de l'élément du manifeste. Ce n'est pas une solution à long terme comme votre targetSdkVersion devra être de 30 ou plus dans le courant de l'année 2021 si vous distribuez votre application sur le Play Store (et peut-être ailleurs).

49voto

Russell A Points 537

Obtenez le destPath avec le nouvel appel API :

String destPath = mContext.getExternalFilesDir(null).getAbsolutePath();

3 votes

Nous pouvons utiliser cette méthode : developer.Android.com/training/data-storage/ ? Qu'en pensez-vous ? :)

3 votes

On peut toujours obtenir la variable d'environnement getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) remplace Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)

0 votes

Mis à jour la méthode dépréciée à ce FIXE erreur "Permission refusée" de createNewFile pour le stockage externe ciblant 29 ! Merci !

31voto

mahmoud mansour Points 467

Pour Android Q, vous pouvez ajouter android:requestLegacyExternalStorage="true" à votre élément dans le manifeste. Ce opte pour dans le modèle de stockage traditionnel, et votre code de stockage externe existant fonctionnera.

<manifest ... >
<!-- This attribute is "false" by default on apps targeting
     Android 10 or higher. -->
  <application android:requestLegacyExternalStorage="true" ... >
    ...
  </application>
</manifest>

Techniquement, vous n'en avez besoin qu'une fois que vous mettez votre targetSdkVersion à 29. Les applications avec des targetSdkVersion les valeurs par défaut pour opter pour le stockage traditionnel et il faudrait android:requestLegacyExternalStorage="false" pour se retirer.

10voto

Hardik Hirpara Points 677

Veuillez utiliser getExternalFilesDir() , getExternalCacheDir() au lieu de Environment.getExternalStorageDirectory() lorsque vous créez un fichier dans Android 10.

Voir la ligne ci-dessous :

val file = File(this.externalCacheDir!!.absolutePath, "/your_file_name")

1 votes

Bonjour, comment pouvons-nous utiliser getExternalFilesDir() avec un chemin personnalisé pour sauvegarder l'image, je veux l'utiliser pour empêcher l'affichage des images dans la Galerie ? Par défaut, l'image est enregistrée dans Andorid/data/packagename/...

0 votes

Vous devrez sauvegarder le fichier dans le répertoire de l'application, puis insérer ce fichier en utilisant l'uri Media.

21 votes

Mauvaise réponse la question réelle comment obtenir /storage/emulated/0/MonDossier/ mais votre réponse /data/user/0/com.example.package/files/MonDossier

8voto

jQuick Points 31

Voici un petit exemple de comment obtenir l'URI d'un fichier si vous voulez prendre une photo en utilisant l'appareil photo par défaut et la stocker dans un dossier DCIM (DCIM/nom_de_l'application/nom_du_fichier.jpg) :

Ouvrez la caméra (n'oubliez pas l'autorisation CAMERA) :

private var photoURI: Uri? = null

private fun openCamera() {
    Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
        photoURI = getPhotoFileUri()
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
        takePictureIntent.resolveActivity(requireActivity().packageManager)?.also {
            startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
        }
    }
}

Et prenez l'URI :

private fun getPhotoFileUri(): Uri {
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
    val fileName = "IMG_${timeStamp}.jpg"

    var uri: Uri? = null
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        val resolver = requireContext().contentResolver
        val contentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
            put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/app_name/")
        }

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

    return uri ?: getUriForPreQ(fileName)
}

private fun getUriForPreQ(fileName: String): Uri {
    val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
    val photoFile = File(dir, "/app_name/$fileName")
    if (photoFile.parentFile?.exists() == false) photoFile.parentFile?.mkdir()
    return FileProvider.getUriForFile(
        requireContext(),
        "ru.app_name.fileprovider",
        photoFile
    )
}

N'oubliez pas la permission WRITE_EXTERNAL_STORAGE pour pre Q et ajoutez un FileProvider à AndroidManifest.xml.

Et obtenir un résultat :

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
        REQUEST_IMAGE_CAPTURE -> {
            photoURI?.let {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    val thumbnail: Bitmap =
                        requireContext().contentResolver.loadThumbnail(
                            it, Size(640, 480), null
                        )
                } else {
                    // pre Q actions
                }
            }
        }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X