page.title=作用域目录访问 page.keywords=Preview、SDK、作用域目录访问 page.tags=Android N @jd:body

本文内容

  1. 访问外部存储目录
  2. 访问可移动介质上的目录
  3. 最佳做法

应用(如照片应用)通常只需要访问外部存储中的特定目录,例如 Pictures 目录。 现有的外部存储访问方法未经专门设计,无法轻松地为这些类型的应用提供目标目录访问。 例如:

Android N 提供简化的全新 API 以访问通用外部存储目录。

访问外部存储目录

使用 StorageManager 类获取适当的 StorageVolume 实例。然后,通过调用该实例的 StorageVolume.createAccessIntent() 方法创建一个 Intent。使用此 Intent 访问外部存储目录。 若要获取所有可用卷的列表,包括可移动介质卷,请使用 StorageManager.getVolumesList()

如果您有关于特定文件的信息,使用 StorageManager.getStorageVolume(File) 来获得包含该文件的 StorageVolume。 调用在 StorageVolume 上的 createAccessIntent() 以访问文件的外部存储目录。

在二级卷(例如外部 SD 卡)上,当调用 StorageVolume.createAccessIntent() 以请求访问整个卷,而不是特定目录时,传入“null”。如果您向主要卷传入“null”,或者如果您传入无效的目录名,StorageVolume.createAccessIntent() 将返回“null”。

以下代码段展示如何在主要共享存储中打开Pictures 目录:

StorageManager sm = (StorageManager)getSystemService(Context.STORAGE_SERVICE);
StorageVolume volume = sm.getPrimaryVolume();
Intent intent = volume.createAccessIntent(Environment.DIRECTORY_PICTURES);
startActivityForResult(intent, request_code);

系统尝试授予对外部目录的访问权限,并使用一个简化的 UI 向用户确认访问权限(如果需要):

图 1. 一个请求访问 Pictures 目录的应用。

如果用户授予访问权限,则系统会调用 onActivityResult() 重写方法,且结果代码为 Activity.RESULT_OK,Intent 数据包含 URI。使用提供的 URI 访问目录信息,与使用存储访问框架返回的 URI 类似。

如果用户不授予访问权限,则系统会调用 onActivityResult() 重写方法,且结果代码为 Activity.RESULT_CANCELED,Intent 数据为 null。

:获得特定外部目录的访问权限也会获得该目录中子目录的访问权限。

访问可移动介质上的目录

若要使用作用域目录访问来访问可移动介质上的目录,首先要添加一个用于侦听 {@link android.os.Environment#MEDIA_MOUNTED} 通知的 {@link android.content.BroadcastReceiver},例如:

<receiver
    android:name=".MediaMountedReceiver"
    android:enabled="true"
    android:exported="true" >
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_MOUNTED" />
        <data android:scheme="file" />
    </intent-filter>
</receiver>

当用户装载可移动介质时,如 SD 卡,系统将发送一则 {@link android.os.Environment#MEDIA_MOUNTED} 通知。此通知在 Intent 数据中提供一个 StorageVolume 对象,您可用它访问可移动介质上的目录。 以下示例访问可移动介质上的 Pictures 目录:

// BroadcastReceiver has already cached the MEDIA_MOUNTED
// notification Intent in mediaMountedIntent
StorageVolume volume = (StorageVolume)
    mediaMountedIntent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME);
volume.createAccessIntent(Environment.DIRECTORY_PICTURES);
startActivityForResult(intent, request_code);

最佳做法

请尽可能保留外部目录访问 URI,这样即不必重复要求用户授予访问权限。 在用户授予访问权限后,使用目录访问 URI 调用 getContentResolver().takePersistableUriPermssion()。 系统将保留此 URI,后续的访问请求将返回 RESULT_OK,且不会向用户显示确认 UI。

如果用户拒绝授予外部目录访问权限,请勿立即再次请求访问权限。 一再不停地请求访问权限会导致非常差的用户体验。 如果用户拒绝了一项请求,而应用再次请求访问,UI 会显示一个 Don't ask again 复选框:

图 1. 应用第二次请求访问可移动介质。

如果用户选择 Don't ask again 并拒绝请求,您的应用向指定目录提出的所有未来请求都将被自动拒绝,并且将不会有请求 UI 呈现给用户。