You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android开发:如何调用系统文件管理器选择文件夹而非文件?

Android 系统文件管理器选择文件夹的实现方案

嘿,这个需求我之前做项目的时候刚好碰到过!你当前用的Intent.ACTION_GET_CONTENT确实是专门用来选择文件的,要实现文件夹选择,得换个官方推荐的Intent Action,而且不同Android版本的适配细节有点不一样,我给你一步步讲清楚:

核心方案:使用ACTION_OPEN_DOCUMENT_TREE

从Android 5.0(API 21)开始,系统就提供了Intent.ACTION_OPEN_DOCUMENT_TREE这个Action,专门用来让用户选择文件夹,这也是官方推荐的标准方式,兼容性最好。

1. 基础调用代码(替代你原来的代码)

把你原来的Intent代码替换成下面这样:

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
// 可选设置:指定打开文件管理器时的初始目录(比如下载目录,API 29+支持)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    Uri initialUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
    intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, initialUri);
}
// 如果你还在用旧的startActivityForResult(不推荐,已废弃)
// startActivityForResult(intent, REQUEST_CODE_FOLDER);
// 推荐用AndroidX的ActivityResultLauncher(适配最新API)
folderPickerLauncher.launch(intent);

2. 处理选择结果(推荐用ActivityResultLauncher)

因为startActivityForResult已经被官方废弃了,我直接给你最新的实现方式:

// 在Activity/Fragment的onCreate里初始化Launcher
ActivityResultLauncher<Intent> folderPickerLauncher = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
            Uri selectedFolderUri = result.getData().getData();
            if (selectedFolderUri != null) {
                // 重要:持久化文件夹的访问权限,避免重启APP后失去权限
                getContentResolver().takePersistableUriPermission(
                    selectedFolderUri,
                    Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                );
                
                // 用DocumentFile来操作选中的文件夹
                DocumentFile selectedFolder = DocumentFile.fromTreeUri(this, selectedFolderUri);
                if (selectedFolder != null && selectedFolder.isDirectory()) {
                    // 示例:遍历文件夹里的所有文件
                    for (DocumentFile file : selectedFolder.listFiles()) {
                        Log.d("FolderPicker", "文件名:" + file.getName() + ",路径URI:" + file.getUri());
                    }
                }
            }
        }
    }
);

低版本兼容(API 21以下)

如果你的APP需要兼容Android 4.4及以下版本,ACTION_OPEN_DOCUMENT_TREE是不支持的,这时候可以尝试用下面的方案,但注意兼容性可能不如官方方案:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("vnd.android.document/directory");
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, REQUEST_CODE_FOLDER);

不过这个方式依赖厂商的ROM实现,有些定制系统可能不支持,所以如果你的用户群体主要是Android 5.0以上,优先用ACTION_OPEN_DOCUMENT_TREE就好。

注意事项

  • 权限问题:使用ACTION_OPEN_DOCUMENT_TREE不需要申请READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE权限,因为是通过系统文件管理器授予的URI级别的权限,而且通过takePersistableUriPermission可以持久化这个权限。
  • Scoped Storage适配:Android 10及以上的Scoped Storage机制下,这种方式是唯一合规的访问外部文件夹的方式,避免了直接操作文件路径的限制。

内容的提问来源于stack exchange,提问作者dezhihuang

火山引擎 最新活动