Environment.getExternalStorageDirectory() 在 API 级别 29 java 中已弃用
Environment.getExternalStorageDirectory() deprecated in API level 29 java
正在 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");
}
});
}
替代方案是什么?
使用 getExternalFilesDir()
、getExternalCacheDir()
或 getExternalMediaDirs()
(Context
上的方法)代替 Environment.getExternalStorageDirectory()
。
或者,修改 mPhotoEditor
以便能够使用 Uri
,然后:
使用 ACTION_CREATE_DOCUMENT
获取 Uri
到用户选择的位置,或
使用 MediaStore
、ContentResolver
和 insert()
为特定类型的媒体(例如图像)获取 Uri
—请参阅 this sample app 演示如何从网站下载 MP4 视频
此外,请注意您的 Uri.fromFile
和 ACTION_MEDIA_SCANNER_SCAN_FILE
应该会在 Android 7.0+ 和 FileUriExposedException
上崩溃。在 Android Q 上,只有 MediaStore
/insert()
选项才能让您的内容快速被 MediaStore
索引。
请注意,如果您的 targetSdkVersion
低于 30,您可以在 Android 10 和 11 上选择退出这些“分区存储”更改,使用 [=31] 中的 android:requestLegacyExternalStorage="true"
=] 清单的元素。 这不是 long-term 解决方案,因为如果您要通过 Play 商店(以及也许在其他地方)。
通过新的 API 调用获取 destPath
:
String destPath = mContext.getExternalFilesDir(null).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 的 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
}
}
}
}
}
在 Android 10.
中创建文件时,请使用 getExternalFilesDir()
、getExternalCacheDir()
而不是 Environment.getExternalStorageDirectory()
见下行:
val file = File(this.externalCacheDir!!.absolutePath, "/your_file_name")
对于 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"
选择退出。
这对我有用
在 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>
Target SDK is 29
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)
}
}
你可以利用 StorageManager
& StorageVolume
类
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;
}
private fun saveImage(bitmap: Bitmap, name: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val resolver = contentResolver
val contentValues = ContentValues()
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name)
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/" + "YOUR_FOLDER")
val imageUri =
resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
val fos = resolver.openOutputStream(imageUri!!)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
fos!!.flush()
fos.close()
toast("Saved to gallery")
} else {
if (isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
val imagesDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM
).toString() + File.separator + "YOUR_FOLDER"
if (!file.exists()) {
file.mkdir()
}
val image = File(imagesDir, "$name.png")
val fos = FileOutputStream(image)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
fos.flush()
fos.close()
} else {
// ask for permission
}
}
}
如果您使用 XAMARIN 并且对所有这些不同的答案感到困惑(像我一样),请按照以下示例操作:
var picture = new Java.IO.File(Environment.DirectoryPictures, "fileName");
我花了一些时间才弄明白。
var tempDir: File = inContext.getExternalFilesDir("/")!!
tempDir = File(tempDir.getAbsolutePath().toString() + "/.IncidentImages/")
tempDir.mkdir()
最近我也遇到了类似的问题,由于我的代码很大,我不想在现有代码中添加新功能,所以我只是简单地改变路径..
Environment.getExternalStorageDirectory() 替换为
context.getExternalFilesDir(null).getAbsolutePath()
代码
private void saveImage() {
if (requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
final String folderPath = this.getExternalFilesDir(null).getAbsolutePath() + "/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");
}
});
}
无需硬编码获取内部存储目录,
权限(对于所有 Android 版本)
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
在 Android 10 及以下版本中,我们可以使用旧权限,但在 Android 10 中,我们必须在应用程序标签(AndroidManifest.xml > 应用程序标签)中使用 requestLegacyExternalStorage。
android:requestLegacyExternalStorage="true"
获取内部存储目录路径:
@Nullable
public static String getInternalStorageDirectoryPath(Context context) {
String storageDirectoryPath;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
if(storageManager == null) {
storageDirectoryPath = null; //you can replace it with the Environment.getExternalStorageDirectory().getAbsolutePath()
} else {
storageDirectoryPath = storageManager.getPrimaryStorageVolume().getDirectory().getAbsolutePath();
}
} else {
storageDirectoryPath = Environment.getExternalStorageDirectory().getAbsolutePath();
}
return storageDirectoryPath;
}
正在 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");
}
});
}
替代方案是什么?
使用 getExternalFilesDir()
、getExternalCacheDir()
或 getExternalMediaDirs()
(Context
上的方法)代替 Environment.getExternalStorageDirectory()
。
或者,修改 mPhotoEditor
以便能够使用 Uri
,然后:
使用
ACTION_CREATE_DOCUMENT
获取Uri
到用户选择的位置,或使用
MediaStore
、ContentResolver
和insert()
为特定类型的媒体(例如图像)获取Uri
—请参阅 this sample app 演示如何从网站下载 MP4 视频
此外,请注意您的 Uri.fromFile
和 ACTION_MEDIA_SCANNER_SCAN_FILE
应该会在 Android 7.0+ 和 FileUriExposedException
上崩溃。在 Android Q 上,只有 MediaStore
/insert()
选项才能让您的内容快速被 MediaStore
索引。
请注意,如果您的 targetSdkVersion
低于 30,您可以在 Android 10 和 11 上选择退出这些“分区存储”更改,使用 [=31] 中的 android:requestLegacyExternalStorage="true"
=] 清单的元素。 这不是 long-term 解决方案,因为如果您要通过 Play 商店(以及也许在其他地方)。
通过新的 API 调用获取 destPath
:
String destPath = mContext.getExternalFilesDir(null).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 的 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
}
}
}
}
}
在 Android 10.
中创建文件时,请使用getExternalFilesDir()
、getExternalCacheDir()
而不是 Environment.getExternalStorageDirectory()
见下行:
val file = File(this.externalCacheDir!!.absolutePath, "/your_file_name")
对于 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"
选择退出。
这对我有用
在 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>
Target SDK is 29
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)
}
}
你可以利用 StorageManager
& StorageVolume
类
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;
}
private fun saveImage(bitmap: Bitmap, name: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val resolver = contentResolver
val contentValues = ContentValues()
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name)
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/" + "YOUR_FOLDER")
val imageUri =
resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
val fos = resolver.openOutputStream(imageUri!!)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
fos!!.flush()
fos.close()
toast("Saved to gallery")
} else {
if (isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
val imagesDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM
).toString() + File.separator + "YOUR_FOLDER"
if (!file.exists()) {
file.mkdir()
}
val image = File(imagesDir, "$name.png")
val fos = FileOutputStream(image)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
fos.flush()
fos.close()
} else {
// ask for permission
}
}
}
如果您使用 XAMARIN 并且对所有这些不同的答案感到困惑(像我一样),请按照以下示例操作:
var picture = new Java.IO.File(Environment.DirectoryPictures, "fileName");
我花了一些时间才弄明白。
var tempDir: File = inContext.getExternalFilesDir("/")!!
tempDir = File(tempDir.getAbsolutePath().toString() + "/.IncidentImages/")
tempDir.mkdir()
最近我也遇到了类似的问题,由于我的代码很大,我不想在现有代码中添加新功能,所以我只是简单地改变路径..
Environment.getExternalStorageDirectory() 替换为
context.getExternalFilesDir(null).getAbsolutePath()
代码
private void saveImage() {
if (requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
final String folderPath = this.getExternalFilesDir(null).getAbsolutePath() + "/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");
}
});
}
无需硬编码获取内部存储目录,
权限(对于所有 Android 版本)
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
在 Android 10 及以下版本中,我们可以使用旧权限,但在 Android 10 中,我们必须在应用程序标签(AndroidManifest.xml > 应用程序标签)中使用 requestLegacyExternalStorage。
android:requestLegacyExternalStorage="true"
获取内部存储目录路径:
@Nullable
public static String getInternalStorageDirectoryPath(Context context) {
String storageDirectoryPath;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
if(storageManager == null) {
storageDirectoryPath = null; //you can replace it with the Environment.getExternalStorageDirectory().getAbsolutePath()
} else {
storageDirectoryPath = storageManager.getPrimaryStorageVolume().getDirectory().getAbsolutePath();
}
} else {
storageDirectoryPath = Environment.getExternalStorageDirectory().getAbsolutePath();
}
return storageDirectoryPath;
}