API级别29 java

时间:2019-07-19 16:23:57

标签: android deprecated android-api-levels

正在使用Android Java(最近将SDK更新到API级别29),现在显示警告,指出该状态

Environment.getExternalStorageDirectory()在API级别29中已弃用

我的代码是

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

有什么替代方法?

10 个答案:

答案 0 :(得分:24)

对于Android Q,您可以将android:requestLegacyExternalStorage="true"添加到清单中的元素。 opts使您进入传统存储模型,并且您现有的外部存储代码将起作用。

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

从技术上讲,仅在将targetSdkVersion更新为29时才需要这样做。具有较低targetSdkVersion值的应用默认会选择使用旧版存储,并且需要android:requestLegacyExternalStorage="false"退出。

答案 1 :(得分:9)

通过新的API调用获取destPath

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

答案 2 :(得分:6)

在Android 10中创建文件时,请使用getExternalFilesDir()getExternalCacheDir()而不是Environment.getExternalStorageDirectory()

请参见以下行:

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

答案 3 :(得分:5)

这对我有用

将此行添加到manifest文件的应用程序标记中

android:requestLegacyExternalStorage="true"

示例

 <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:requestLegacyExternalStorage="true"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

 </application>

目标SDK为29

  defaultConfig {
        minSdkVersion 16
        targetSdkVersion 29
        multiDexEnabled true
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

答案 4 :(得分:3)

这有效

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    contentResolver?.also { resolver ->
        val contentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, "Image_"+".jpg")
            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg")
            put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator+ "TestFolder")
        }
        val imageUri: Uri? = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
            fos = imageUri?.let { resolver.openOutputStream(it) }
            bitmap.compress(Bitmap.CompressFormat.JPEG,100,fos)
            Objects.requireNonNull(fos)
    }
}

答案 5 :(得分:1)

您可以使用 StorageManagerStorageVolume

StorageVolume.getPrimaryStorageVolume():此卷与 Environment#getExternalStorageDirectory() 和 Context#getExternalFilesDir(String) 返回的存储设备相同。

    public String myGetExternalStorageDir() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
            return getPrimaryStorageVolumeForAndroid11AndAbove();
        else
            return getPrimaryStorageVolumeBeforeAndroid11();
    }

    @TargetApi(Build.VERSION_CODES.R)
    private String getPrimaryStorageVolumeForAndroid11AndAbove() {
        StorageManager myStorageManager = (StorageManager) ctx.getSystemService(Context.STORAGE_SERVICE);
        StorageVolume mySV = myStorageManager.getPrimaryStorageVolume();
        return mySV.getDirectory().getPath();
    }

    private String getPrimaryStorageVolumeBeforeAndroid11() {
        String volumeRootPath = "";
        StorageManager myStorageManager = (StorageManager) ctx.getSystemService(Context.STORAGE_SERVICE);
        StorageVolume mySV = myStorageManager.getPrimaryStorageVolume();
        Class<?> storageVolumeClazz = null;

        try {
            storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
            Method getPath = storageVolumeClazz.getMethod("getPath");
            volumeRootPath = (String) getPath.invoke(mySV);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return volumeRootPath;
    }

答案 6 :(得分:0)

使用getExternalFilesDir()getExternalCacheDir()getExternalMediaDir()Context上的方法)代替Environment.getExternalStorageDirectory()

或者,将mPhotoEditor修改为可以与Uri一起使用,然后:

  • 使用ACTION_CREATE_DOCUMENTUri移至用户选择的位置,或者

  • 使用MediaStoreContentResolverinsert()获取特定媒体类型(例如图像)的Uri -请参阅{{3 }}演示了如何从网站下载MP4视频

此外,请注意,带有Uri.fromFile的{​​{1}}在带有ACTION_MEDIA_SCANNER_SCAN_FILE的Android 7.0及更高版本上应该会崩溃。在Android Q上,只有FileUriExposedException / MediaStore选项将使您的内容迅速被insert()索引。

有关Android Q如何影响外部存储的更多信息,请参见this sample app

答案 7 :(得分:0)

这是一个小示例,如果您想使用默认相机拍照并将其存储在DCIM文件夹(DCIM / app_name / filename.jpg)中,如何获取文件的URI:

打开相机(记住有关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)
        }
    }
}

并获取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
    )
}

不要忘记对Q的WRITE_EXTERNAL_STORAGE权限,并将FileProvider添加到AndroidManifest.xml。

并获得结果:

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

答案 8 :(得分:0)

// Print SubStrings using recursion 

void pss(string s, int start, int end)
{
    if(start==s.length()-1)
    {
        cout<<s.substr(start)<<endl;
        return;
    }
    if(end==s.length()+1)
    {
        start++;
        end=start+1;
        pss(s,start,end);
    }
    else if( start<=s.length()&&end<=s.length())
    {
        cout<<s.substr(start,end-start)<<endl;
        pss(s,start,end+1);
    }
}


 int main()
{
 string s;
 cin>>s;
 pss(s,0,1); 
 return 0;
}

答案 9 :(得分:0)

如果您使用 XAMARIN 并且对所有这些不同的答案感到困惑(像我一样),请按照以下示例操作:

var picture = new Java.IO.File(Environment.DirectoryPictures, "fileName");

我花了一些时间才弄明白。