web-dev-qa-db-fra.com

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

En travaillant sur Android Java, SDK récemment mis à jour au niveau de l'API 29, un avertissement s'affiche, indiquant que

Environment.getExternalStorageDirectory() est obsolète au niveau de l'API 29

Mon code est

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 pour cela?

42
Noaman Akram

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

Ou, modifiez mPhotoEditor pour pouvoir travailler avec un Uri, puis:

  • Utilisez ACTION_CREATE_DOCUMENT Pour obtenir un Uri à l'emplacement choisi par l'utilisateur, ou

  • Utilisez MediaStore, ContentResolver et insert() pour obtenir un Uri pour un type particulier de support (par exemple, une image) - voir 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 Avec ACTION_MEDIA_SCANNER_SCAN_FILE Devrait planter sur Android 7.0+ avec un FileUriExposedException. Sur Android Q, seule l'option MediaStore/insert() obtiendra votre contenu indexé par MediaStore rapidement.

Voir cet article de blog pour en savoir plus sur la manière dont Android Q a affecté le stockage externe.

40
CommonsWare

Obtenez le destPath avec le nouvel appel d'API:

String destPath = mContext.getExternalFilesDir(null).getAbsolutePath();
14
Russell A

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

Ouvrez la caméra (rappelez-vous de 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 obtenez 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 l'autorisation WRITE_EXTERNAL_STORAGE pour pré Q et ajoutez un FileProvider à AndroidManifest.xml.

Et obtenez 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
                }
            }
        }
    }
}
1
bitvale