很多好问题,让我们深入研究。:)
你如何使用它?
这是与 KitKat 中的存储访问框架交互的一个很好的教程:
https://developer.android.com/guide/topics/providers/document-provider.html#client
与 Lollipop 中的新 API 交互非常相似。要提示用户选择目录树,您可以启动如下意图:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, 42);
然后在您的 onActivityResult() 中,您可以将用户选择的 Uri 传递给新的 DocumentFile 助手类。这是一个快速示例,它列出了所选目录中的文件,然后创建了一个新文件:
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode == RESULT_OK) {
Uri treeUri = resultData.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
// List all existing files inside picked directory
for (DocumentFile file : pickedDir.listFiles()) {
Log.d(TAG, "Found file " + file.getName() + " with size " + file.length());
}
// Create a new file and write into it
DocumentFile newFile = pickedDir.createFile("text/plain", "My Novel");
OutputStream out = getContentResolver().openOutputStream(newFile.getUri());
out.write("A long time ago...".getBytes());
out.close();
}
}
返回的 UriDocumentFile.getUri()
足够灵活,可以与可能不同的平台 API 一起使用。例如,您可以使用Intent.setData()
with共享它Intent.FLAG_GRANT_READ_URI_PERMISSION
。
如果您想从本机代码访问该 Uri,您可以调用ContentResolver.openFileDescriptor()
然后使用ParcelFileDescriptor.getFd()
ordetachFd()
来获取传统的 POSIX 文件描述符整数。
如何检查是否可以访问文件/文件夹?
默认情况下,通过存储访问框架意图返回的 Uris不会在重新启动后保留。平台“提供”了持久化权限的能力,但如果你愿意,你仍然需要“获取”权限。在我们上面的例子中,你会调用:
getContentResolver().takePersistableUriPermission(treeUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
ContentResolver.getPersistedUriPermissions()
您始终可以通过API找出您的应用程序可以访问的持久授权。如果您不再需要访问持久化的 Uri,您可以使用ContentResolver.releasePersistableUriPermission()
.
这在 KitKat 上可用吗?
不,我们不能追溯性地向旧版本的平台添加新功能。
我可以查看哪些应用程序可以访问文件/文件夹吗?
目前没有显示此内容的 UI,但您可以在adb shell dumpsys activity providers
输出的“Granted Uri Permissions”部分中找到详细信息。
如果在同一设备上为多个用户安装应用程序会怎样?
Uri 权限授予在每个用户的基础上是隔离的,就像所有其他多用户平台功能一样。也就是说,在两个不同用户下运行的同一个应用程序没有重叠或共享的 Uri 权限授予。
可以撤销权限吗?
支持 DocumentProvider 可以随时撤销权限,例如删除基于云的文档时。发现这些被撤销权限的最常见方法是当它们从ContentResolver.getPersistedUriPermissions()
上面提到的消失时。
每当为授权中涉及的任一应用程序清除应用程序数据时,权限也会被撤销。
会在选定的文件夹上递归地请求权限吗?
是的,ACTION_OPEN_DOCUMENT_TREE
意图使您可以递归访问现有和新创建的文件和目录。
这允许多选吗?
是的,从 KitKat 开始就支持多项选择,您可以通过EXTRA_ALLOW_MULTIPLE
在启动ACTION_OPEN_DOCUMENT
意图时进行设置来允许它。您可以使用Intent.setType()
或EXTRA_MIME_TYPES
缩小可以选择的文件类型:
http://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT
模拟器上有没有办法尝试新的 API?
是的,主共享存储设备应该出现在选择器中,即使在模拟器上也是如此。如果您的应用仅使用存储访问框架来访问共享存储,则您根本不需要READ/WRITE_EXTERNAL_STORAGE
权限,可以删除它们或使用该android:maxSdkVersion
功能仅在旧平台版本上请求它们。
当用户用另一张 SD 卡替换 SD 卡时会发生什么?
当涉及到物理媒体时,底层媒体的 UUID(如 FAT 序列号)总是被烧录到返回的 Uri 中。系统使用它来将您连接到用户最初选择的媒体,即使用户在多个插槽之间交换媒体。
如果用户换了第二张卡,您需要提示获得对新卡的访问权限。由于系统会根据每个 UUID 记住授权,因此如果用户稍后重新插入原始卡,您将继续拥有先前授予的访问权限。
http://en.wikipedia.org/wiki/Volume_serial_number