Android API级别29 java中不推荐使用Environment.getExternalStorageDirectory()
在android Java上工作,最近将SDK更新为API级别29,现在显示了一条警告,指出 API级别29中不推荐使用Environment.getExternalStorageDirectory 我的代码是Android API级别29 java中不推荐使用Environment.getExternalStorageDirectory(),android,deprecated,android-api-levels,Android,Deprecated,Android Api Levels,在android Java上工作,最近将SDK更新为API级别29,现在显示了一条警告,指出 API级别29中不推荐使用Environment.getExternalStorageDirectory 我的代码是 private void saveImage() { if (requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { final String folderPath = Environment.getE
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");
}
});
}
有什么替代方法?在上下文上使用getExternalFilesDir、getExternalCacheDir或getExternalMediaDirs方法,而不是Environment.getExternalStorageDirectory
或者,修改mPhotoEditor以使用Uri,然后:
使用ACTION_CREATE_DOCUMENT获取用户选择位置的Uri,或
使用MediaStore、ContentResolver和insert获取特定类型媒体(例如图像)的Uri-请参阅演示如何从网站下载MP4视频
另外,请注意,您的Uri.fromFile和ACTION_MEDIA_SCANNER_SCAN_文件应该在Android 7.0+上崩溃,并且出现FileUriExposedException。在Android Q上,只有MediaStore/insert选项才能让MediaStore快速索引您的内容
请注意,如果targetSdkVersion低于30,则可以在清单的元素中使用Android:requestLegacyExternalStorage=true,选择退出Android 10和11上的这些范围存储更改。这不是一个长期的解决方案,因为如果您通过Play Store或其他地方分发应用程序,您的targetSdkVersion在2021年的某个时候将需要达到30或更高版本。使用新的API调用获取destPath:
字符串destPath=mContext.getExternalFilesDirnull.getAbsolutePath;
这是一个小示例,如果您想使用默认相机拍照并将其存储在DCIM文件夹DCIM/app_name/filename.jpg中,如何获取文件的URI: 打开相机记住关于相机权限:
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
)
}
不要忘记为pre Q写入外部存储权限,并向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
}
}
}
}
}
在Android 10中创建文件时,请使用getExternalFilesDir、getExternalCacheDir而不是Environment.getExternalStorageDirectory
见下一行:
val file=Filethis.externalCacheDir!!。绝对路径,/您的文件名
对于Android Q,您可以将Android:requestLegacyExternalStorage=true添加到清单中的元素中。这将把您引入到遗留存储模型中,并且您现有的外部存储代码将正常工作 ... 从技术上讲,您只需要在将targetSdkVersion更新到29之后才需要它。targetSdkVersion值较低的应用程序默认选择传统存储,并且需要android:requestLegacyExternalStorage=false才能选择退出。这对我很有效 在清单文件的应用程序标记中添加此行 范例 这起作用了
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)
}
}
您可以使用StorageManager和StorageVolume类
:此卷是EnvironmentgetExternalStorageDirectory和ContextgetExternalFilesDirString返回的同一存储设备
公共字符串myGetExternalStorageDir{
如果Build.VERSION.SDK\u INT>=Build.VERSION\u code.R
返回GetPrimaryStorageVolumeForandRoida11及以上;
其他的
返回getPrimaryStorageVolumeBeforeAndroid11;
}
@TargetApiBuild.VERSION_code.R
私有字符串GetPrimaryStorageVolumeForandRoida11及以上{
StorageManager myStorageManager=StorageManager ctx.getSystemServiceContext.STORAGE\u服务;
StorageVolume mySV=myStorageManager.getPrimaryStorageVolume;
返回mySV.getDirectory.getPath;
}
私有字符串getPrimaryStorageVolumeBeforeAndroid11{
字符串volumeRootPath=;
StorageManager myStorageManager=StorageManager ctx.getSystemServiceContext.STORAGE\u服务;
StorageVolume mySV=myStorageManager.getPrimaryStorageVolume;
类storageVolumeClazz=null;
试一试{
storageVolumeClazz=Class.forNameandroid.os.storage.StorageVolume;
方法getPath=storageVolumeClazz.getMethodgetPath;
volumeRootPath=字符串getPath.invokemySV;
}捕获异常e{
e、 打印跟踪;
}
返回卷路径;
}
亲爱的@commonware,如果我们在真实生活中相遇,请提醒我,我欠你一杯啤酒,感谢你的博客帖子。当我将targetSdk级别提升到29级时,我花了整整一个下午的时间找出某个外部库停止工作的原因。现在我知道了为什么…使用getExternalFilesDir和getExternalCacheDir可以与api 29一起工作,但是当应用程序未安装时,所有数据都将使用此方法删除。。。如果在应用程序标记android:requestLegacyExternalStorage=true中使用此属性,则也可以用于api 29。当应用程序未安装的文件名退出但数据removed@miladsalimi:对不起,我不明白你的问题。我建议您提出一个单独的堆栈溢出问题,详细解释您关心的是什么。上下文中没有getExternalMediaDir,请自己查看:getExternalMediaDirs是d
eprecated,也可以查看:getExternalFilesDir和getExternalCacheDir在应用程序卸载时都会被删除。请查看相同的URL。所以,上面的任何一个都不能替代Environment.getExternalStorageDirectory。这不是我的用例,而是上面topicstarter的用例。我们可以使用以下方法:?你觉得怎么样仍然可以获取环境变量getExternalFilesDirEnvironment.DIRECTORY\u DOWNLOADS替换environment.getExternalStoragePublicDirectoryEnvironment.DIRECTORY\u DOWNLOADS将不推荐的方法更新为此修复了createNewFile针对外部存储的权限拒绝错误29!非常感谢。这不是公共目录我试过这段代码,它在三星a70安卓10中对我不起作用。使用此代码时未创建目录。getExternalStorageDirectory正在工作,但已弃用..有解决方案吗?它也是弃用的Post-it java pleaseHi,我们如何使用getExternalFilesDir和自定义路径来保存图像,我想使用它来防止将图像显示到库中?默认情况下,它保存到android/data/packagename/…您需要将文件保存到app目录,然后使用媒体插入此文件。回答错误..实际问题如何获取/storage/emulated/0/MyFolder/但您的anser/data/user/0/com.example.package/files/MyFolderi尝试了此代码,三星a70安卓10对我不起作用。使用此代码时未创建目录。getExternalStorageDirectory正在工作,但已被弃用..有解决方案吗?这篇文章保存了我对最新版本的Android Studio中存储外部存储数据的解决方案的搜索,其中包含一个早期开发的代码,持续了8个小时。谢谢。它将一直工作到API 29。警告:将应用程序更新为目标Android 11 API级别30后,当应用程序在Android 11设备上运行时,系统将忽略requestLegacyExternalStorage属性,因此应用程序必须准备好支持作用域存储,并为这些设备上的用户迁移应用程序数据。仍然得到相同的错误不推荐
<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>
defaultConfig {
minSdkVersion 16
targetSdkVersion 29
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
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)
}
}