将Android11中的文件保存到外部存储(SDK 30)
Saving files in Android 11 to external storage(SDK 30)
我正在 Android 11(SDK 版本 30)上编写一个新应用程序,但我根本找不到关于如何将文件保存到外部存储器的示例。
我阅读了他们的文档,现在知道他们基本上忽略了清单权限(READ_EXTERNAL_STORAGE
和 WRITE_EXTERNAL_STORAGE
)。他们还忽略 manifest.xml 应用程序标记中的 android:requestLegacyExternalStorage="true"
。
在他们的文档 https://developer.android.com/about/versions/11/privacy/storage 中,他们写道您需要启用 DEFAULT_SCOPED_STORAGE
和 FORCE_ENABLE_SCOPED_STORAGE
标志以在您的应用程序中启用分区存储。
我必须在哪里启用这些?
当我完成后,如何以及何时获得写入外部存储的实际权限?有人可以提供工作代码吗?
我想保存 .gif、.png 和 .mp3 文件。所以我不想给画廊写信。
提前致谢。
您可以将文件保存到外部存储的 public 目录中。
喜欢文档、下载、DCIM、图片等。
按照版本 10 之前的常规方式。
对应所有 Api,包括 Api 30,Android 11 :
public static File commonDocumentDirPath(String FolderName)
{
File dir = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
{
dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/" + FolderName);
}
else
{
dir = new File(Environment.getExternalStorageDirectory() + "/" + FolderName);
}
// Make sure the path directory exists.
if (!dir.exists())
{
// Make it, if it doesn't exit
boolean success = dir.mkdirs();
if (!success)
{
dir = null;
}
}
return dir;
}
现在,使用这个 commonDocumentDirPath
来保存文件。
来自评论的旁注,getExternalStoragePublicDirectory
与某些范围现在正在使用 Api 30,Android 11。干杯!感谢 CommonsWare 提示。
**最简单的答案和测试(Java)**
private void createFile(String title) {
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("text/html");
intent.putExtra(Intent.EXTRA_TITLE, title);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Uri.parse("/Documents"));
}
createInvoiceActivityResultLauncher.launch(intent);
}
private void createInvoice(Uri uri) {
try {
ParcelFileDescriptor pfd = getContentResolver().
openFileDescriptor(uri, "w");
if (pfd != null) {
FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
fileOutputStream.write(invoice_html.getBytes());
fileOutputStream.close();
pfd.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/////////////////////////////////////////////////////
// You can do the assignment inside onAttach or onCreate, i.e, before the activity is displayed
String invoice_html;
ActivityResultLauncher<Intent> createInvoiceActivityResultLauncher;
@Override
protected void onCreate(Bundle savedInstanceState) {
invoice_html = "<h1>Just for testing received...</h1>";
createInvoiceActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Uri uri = null;
if (result.getData() != null) {
uri = result.getData().getData();
createInvoice(uri);
// Perform operations on the document using its URI.
}
}
});
我正在使用这个方法,它真的对我有用
我希望我能帮助你。有什么不明白的可以随时问我
Bitmap imageBitmap;
OutputStream outputStream ;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
{
ContentResolver resolver = context.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME,"Image_"+".jpg");
contentValues.put(MediaStore.MediaColumns.MIME_TYPE,"image/jpeg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH,Environment.DIRECTORY_PICTURES + File.separator+"TestFolder");
Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues);
try {
outputStream = resolver.openOutputStream(Objects.requireNonNull(imageUri) );
imageBitmap.compress(Bitmap.CompressFormat.JPEG,100,outputStream);
Objects.requireNonNull(outputStream);
Toast.makeText(context, "Image Saved", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(context, "Image Not Not Saved: \n "+e, Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
清单文件(添加权限)
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
我正在 Android 11(SDK 版本 30)上编写一个新应用程序,但我根本找不到关于如何将文件保存到外部存储器的示例。
我阅读了他们的文档,现在知道他们基本上忽略了清单权限(READ_EXTERNAL_STORAGE
和 WRITE_EXTERNAL_STORAGE
)。他们还忽略 manifest.xml 应用程序标记中的 android:requestLegacyExternalStorage="true"
。
在他们的文档 https://developer.android.com/about/versions/11/privacy/storage 中,他们写道您需要启用 DEFAULT_SCOPED_STORAGE
和 FORCE_ENABLE_SCOPED_STORAGE
标志以在您的应用程序中启用分区存储。
我必须在哪里启用这些?
当我完成后,如何以及何时获得写入外部存储的实际权限?有人可以提供工作代码吗?
我想保存 .gif、.png 和 .mp3 文件。所以我不想给画廊写信。
提前致谢。
您可以将文件保存到外部存储的 public 目录中。
喜欢文档、下载、DCIM、图片等。
按照版本 10 之前的常规方式。
对应所有 Api,包括 Api 30,Android 11 :
public static File commonDocumentDirPath(String FolderName)
{
File dir = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
{
dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/" + FolderName);
}
else
{
dir = new File(Environment.getExternalStorageDirectory() + "/" + FolderName);
}
// Make sure the path directory exists.
if (!dir.exists())
{
// Make it, if it doesn't exit
boolean success = dir.mkdirs();
if (!success)
{
dir = null;
}
}
return dir;
}
现在,使用这个 commonDocumentDirPath
来保存文件。
来自评论的旁注,getExternalStoragePublicDirectory
与某些范围现在正在使用 Api 30,Android 11。干杯!感谢 CommonsWare 提示。
**最简单的答案和测试(Java)**
private void createFile(String title) {
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("text/html");
intent.putExtra(Intent.EXTRA_TITLE, title);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Uri.parse("/Documents"));
}
createInvoiceActivityResultLauncher.launch(intent);
}
private void createInvoice(Uri uri) {
try {
ParcelFileDescriptor pfd = getContentResolver().
openFileDescriptor(uri, "w");
if (pfd != null) {
FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
fileOutputStream.write(invoice_html.getBytes());
fileOutputStream.close();
pfd.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/////////////////////////////////////////////////////
// You can do the assignment inside onAttach or onCreate, i.e, before the activity is displayed
String invoice_html;
ActivityResultLauncher<Intent> createInvoiceActivityResultLauncher;
@Override
protected void onCreate(Bundle savedInstanceState) {
invoice_html = "<h1>Just for testing received...</h1>";
createInvoiceActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Uri uri = null;
if (result.getData() != null) {
uri = result.getData().getData();
createInvoice(uri);
// Perform operations on the document using its URI.
}
}
});
我正在使用这个方法,它真的对我有用 我希望我能帮助你。有什么不明白的可以随时问我
Bitmap imageBitmap;
OutputStream outputStream ;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
{
ContentResolver resolver = context.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME,"Image_"+".jpg");
contentValues.put(MediaStore.MediaColumns.MIME_TYPE,"image/jpeg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH,Environment.DIRECTORY_PICTURES + File.separator+"TestFolder");
Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues);
try {
outputStream = resolver.openOutputStream(Objects.requireNonNull(imageUri) );
imageBitmap.compress(Bitmap.CompressFormat.JPEG,100,outputStream);
Objects.requireNonNull(outputStream);
Toast.makeText(context, "Image Saved", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(context, "Image Not Not Saved: \n "+e, Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
清单文件(添加权限)
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />