返回

Android 11文件管理适配扫盲指南,助您轻松上手!

Android

Android 11 的文件管理革新:开发者适配指南

Android 11 中的文件管理革命

Android 11 在文件管理方面进行了全面改革,带来了全新的存储访问框架 (SAF)、分区存储和外部存储调整。这些变化旨在增强安全性和用户隐私,同时也为开发者带来了新的挑战。

存储访问框架 (SAF)

SAF 统一了对所有存储设备的访问,包括内部存储、外部存储和云存储。应用不再可以直接访问文件系统,而是必须使用 SAF 来请求对文件的访问权限。这有助于防止恶意应用访问用户数据。

分区存储

分区存储将内部存储划分为两个分区:

  • 应用分区: 仅用于存储应用自己的数据,例如应用设置和缓存。
  • 媒体分区: 用于存储用户生成的数据,例如照片、视频和音乐。

这种分区有助于将应用数据与用户数据分隔开来,增强了安全性。

外部存储

Android 11 中,应用不再能够直接访问外部存储。必须通过 SAF 来访问外部存储,这提供了更严格的访问控制。

开发者适配指南

为了在 Android 11 上顺畅运行,开发者需要对应用进行适配:

使用 SAF 访问文件

使用 SAF 访问文件的步骤:

  • 创建一个 Intent,指定要执行的操作(例如,选择文件或创建文件)。
  • 设置 Intent 的过滤器,以指定要访问的文件类型。
  • 启动 Intent,并处理用户选择的或创建的文件。

处理分区存储

  • 将用户生成的数据存储到媒体分区。
  • 将应用专属数据存储到应用分区。

处理外部存储

  • 通过 SAF 访问外部存储。
  • 不要直接访问外部存储。

注意事项

  • 更新应用的目标 SDK 版本到 Android 11 或更高。
  • 使用 AndroidX 库。
  • 彻底测试应用,确保在 Android 11 设备上正常运行。

常见问题解答

1. 如何使用 SAF 获取文件的读取权限?

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, REQUEST_CODE_OPEN_DOCUMENT);

2. 如何将文件写入媒体分区?

Uri uri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, "image.jpg");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
Uri newUri = getContentResolver().insert(uri, values);
OutputStream outputStream = getContentResolver().openOutputStream(newUri);
// 将数据写入输出流...

3. 为什么我的应用无法访问外部存储?

确保已通过 SAF 访问外部存储,并且已请求并获得了必要的权限。

4. 如何将应用数据从内部存储迁移到媒体分区?

// 获取要迁移的数据的 URI
Uri dataUri = MediaStore.Downloads.EXTERNAL_CONTENT_URI;

// 创建新的内容 URI,指向媒体分区
Uri mediaUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL);

// 迁移数据
try {
    getContentResolver().move(dataUri, mediaUri);
} catch (IOException e) {
    // 处理错误
}

5. 如何处理SAF授权变更?

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == REQUEST_CODE_OPEN_DOCUMENT && resultCode == RESULT_OK) {
        // 检查授权是否已被撤销
        if (DocumentFile.isDocumentUri(this, data.getData())) {
            DocumentFile documentFile = DocumentFile.fromSingleUri(this, data.getData());
            if (documentFile != null && !documentFile.canRead()) {
                // 授权已被撤销,提示用户重新授权
                requestReadAccess(documentFile);
            }
        }
    }
}