代码之家  ›  专栏  ›  技术社区  ›  tfrysinger

我的自定义文档提供程序是否应使用ParcelFileDescriptor来流式处理所选文件?

  •  1
  • tfrysinger  · 技术社区  · 7 年前

    在我的应用程序中,我正在使用 Glide 用于处理/显示图像,以及 ExoPlayer 用于显示视频。两者都可以将一个直接的uri链接到一个文件,并将处理内容流、缓冲、调整大小、处理缓存管理等,换句话说,所有的硬东西!

    这个uri的格式以及在使用android文件选择器和自定义文档提供程序时在封面下发生的事情是这里问题的关键。

    因为我想要一个无缝的用户体验来选择应用程序中使用的图像、视频和音频,无论所需的文件是移动设备本地的还是互联网上的,所以我决定使用android文件选择器。这意味着我必须写或提供 DocumentsProvider 实例与每个不支持SAF的在线资源(即Dropbox、Snapchat、Instagram等)的存储访问框架保持一致。

    尽管需要一点技巧,但编写documentsProvider类并不太困难。

    问题开始于这样一个事实,即从选择器返回的uri(以及作为持久uri存储以供我的应用程序稍后使用的内容)是 content:// 变化-它不是 http:// https:// 滑翔机/外游戏者通常使用的类型。

    例如,假设 内容:// 字符串类型最终用作 .load() 方法如下:

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

    接下来发生的是 文档提供程序 与该uri关联的实例最终获得 openDocument() 打电话来。例如,我编写了一个自定义DropboxProvider。从我存储在应用程序数据库中的选择器返回的uri如下所示:

    content://authority_string/document/XXX-YYY-ZZZ 是的。

    当将字符串传递给 load() 滑翔的方法,我的 打开文档() 调用DropboxProvider类的方法,在那里我解析出文档ID,登录到Dropbox,并使用它们的API在本地拦截文件并返回 ParcelFileDescriptor 包装 File 指向下载文件的对象。然后调用方可以适当地解析这个描述符对象,并正确地滑动加载它。

    这一切都很好。

    然而,让我吃惊的是,这种方法并不是最优的,原因有很多,主要是glide/exoplayer不知道如何在dropbox上定位文件,一旦他们有了直接的链接,他们就支持抓取、缓冲、流和缓存管理等,可能比我做的要好得多。

    在我看来,最好遵循“关注点分离”的方法,不要让我的应用程序承担“拥有”下载/流和缓存管理的责任。只是自己有“鉴定档案”的责任。

    所以这真的是我问题的症结所在——就谁负责什么而言,这里最好的“截止线”在哪里?

    我无法回避这样一个事实:选择者的结果是 内容:// 链接这就是存储访问框架的构建方式。

    但我可以做的是增加我的提供者来提前识别直接链接,并在用户最初选择文件时将其返回到光标中。完成文件选择后,使用标准resolver()方法将该信息捕获到 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,而不是 内容:// 基于uri,我现在从文件选择器返回。这将允许glide/exoplayer完全处理获取这些文件(不再调用我的自定义提供程序来解决获取文件的问题)。

    还是继续使用 内容:// 在调用glide/exoplayer时键入uri并研究如何创建 包文件描述符 将管道包装到实际文件并从 打开文档() 是吗?这似乎暗示了伊恩 fine article 在本节中 找到文件的核心:字节! 是的。

    但是,在这种情况下,这样做肯定会重复这两个工具中已经存在的工作(而且我还没有找到以这种方式使用ParcelFileDescriptor的示例)。

    0 回复  |  直到 7 年前
    推荐文章