我的自定义DocumentsProvider是否应该使用ParcelFileDescriptor来流式传输所选文件?

时间:2019-01-22 00:01:09

标签: android streaming uri android-contentprovider

在我的应用中,我正在使用Glide处理/显示图像,并使用ExoPlayer显示视频。两者都可以直接指向文件的URI链接,并且将处理内容的流式传输,对其进行缓冲,调整其大小,处理缓存管理等。换句话说,所有的难题!

此URI的格式以及使用Android File Chooser和自定义文档提供程序时幕后发生的事情是导致此问题的关键。

由于我想要一个无缝的用户体验来选择要在应用程序中使用的图像,视频和音频(无论所需文件是移动设备本地还是Internet上的本地存储),所以我决定使用Android File Chooser。这意味着我必须为每个尚不支持SAF的在线资源(即DropBox,SnapChat,Instagram等)编写或提供一个DocumentsProvider实例,以符合存储访问框架的要求。

尽管要花些时间才能掌握,但编写DocumentsProvider类并不是很困难。

问题始于以下事实:从选择器返回的URI(以及我存储为持久URI以便以后由我的应用使用的内容)的种类为content://,而不是Glide / ExoPlayer通常使用的http://https://类型。

因此,例如,假设字符串content://最终用作以下.load()方法的参数:

            GlideApp.with(context)
                    .load(Uri.parse(media.getPathToMedia()))
                    .apply(RequestOptions.fitCenterTransform())
                    .placeholder(placeHolder)
                    .error(R.drawable.ic_image_error)
                    .into(imageView);

接下来发生的是与该URI关联的DocumentsProvider实例最终得到一个openDocument()调用。因此,例如,我编写了一个自定义的DropboxProvider。从我存储在应用程序数据库中的选配器返回的URI类似于:

content://authority_string/document/XXX-YYY-ZZZ

将该字符串传递给Glide的load()方法时,将调用我的DropboxProvider类的openDocument()方法,然后在其中解析文档ID,登录到DropBox并使用它们可以在本地捕获文件并返回ParcelFileDescriptor并包装指向该下载文件的File对象的API。然后,调用者可以适当地解析此描述符对象,并且Glide可以正确加载它。

一切正常。

但是,令我惊讶的是,这种方法并不是最佳的几种原因,其主要原因是,尽管Glide / ExoPlayer不知道如何在DropBox上定位文件,但是一旦它们直接链接到它们所支持的提取,缓冲,流和缓存管理等可能比我做的要好得多。

在我看来,最好遵循“关注点分离”方法,而不要让我的应用程序“拥有”下载/流和缓存管理职责。只需拥有“文件标识”责任。

这真的是我的问题的关键-就谁负责什么而言,最好的“截止”线在哪里?

选择器的结果是一个content://链接,这使我无法回避。这就是存储访问框架的构建方式。

但是我能做的是扩充我的提供程序以提前识别该直接链接,并在用户最初选择文件时将其返回到Cursor中。然后,在完成文件选择后,使用标准的Res​​olver()方法将该信息捕获到我的Media对象中,然后我将该对象持久保存到数据库中:

public static void populateMediaFromUri(Context context, Media media, Uri uri) {
    *
    *
    *
    String path = null;

    cursor = context.getContentResolver().query(uri, null, null, null, null);
    try {
        if ( cursor != null && cursor.moveToFirst() ) {

            String directLink = cursor.getString(cursor.getColumnIndex(AbstractStorageProvider.COLUMN_DIRECT_LINK));
            if ( directLink == null ) {
                path = uri.toString();
            } else {
                path = directLink;
            }

            *
            *
            *
            media.setPathToMedia(path);

        }
    } catch (Exception e ) {
        Timber.d("Error resolving to path, requested was %s, error was %s", uri.getPath(), e.getMessage());
    } finally {
        if ( cursor != null ) {
            cursor.close();
        }
    }

然后,我可以稍后使用该直接链接路径传递给Glide或ExoPlayer,而不是从文件选择器中获取的基于content://的URI。这将允许Glide / ExoPlayer完全处理获取这些文件的操作(不再调用我的自定义提供程序来解析获取文件的操作)。

还是我在对Glide / ExoPlayer的调用中继续使用content://类型的URI,并研究如何创建将管道包装到实际文件并从{{1 }}?在Ian的fine article 获取文档的要点:字节! 中,这似乎暗示了这是一种可能的方法。

但是再次,在这种情况下,这样做确实可以确证这两个工具中已经存在的工作(并且我还无法找到以这种方式使用ParcelFileDescriptor的示例)。

0 个答案:

没有答案