Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/216.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Android上实现DocumentsProvider for the cloud的问题_Android_Android Contentprovider_Storage Access Framework - Fatal编程技术网

在Android上实现DocumentsProvider for the cloud的问题

在Android上实现DocumentsProvider for the cloud的问题,android,android-contentprovider,storage-access-framework,Android,Android Contentprovider,Storage Access Framework,我制作了自定义文档提供程序实现,其中文件实际上存储在服务器上 我遵循了文档,因此提供商大部分时间都在工作,但我在某些应用程序中遇到了问题,即: 1) Gmail附加来自我的提供商的文件: 最初是我的公共ParcelFileDescriptor openDocument 是这样的: ParcelFileDescriptor[] pipe=null; pipe=ParcelFileDescriptor.createPipe(); OutputStream out = new ParcelFileDe

我制作了自定义文档提供程序实现,其中文件实际上存储在服务器上

我遵循了文档,因此提供商大部分时间都在工作,但我在某些应用程序中遇到了问题,即:

1) Gmail附加来自我的提供商的文件: 最初是我的公共ParcelFileDescriptor openDocument 是这样的:

ParcelFileDescriptor[] pipe=null;
pipe=ParcelFileDescriptor.createPipe();
OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]);
new TransferThread(file_id,out).start();
return pipe[0];
但这在Gmail上根本不起作用,我的水管坏了。 如果我第一次用相同的方法下载文件(阻塞),它就会工作

Original适用于大多数其他应用程序

2) Blackberry Hub-我无论如何都无法让它工作,因为它似乎在主线程上调用提供程序方法

我会放弃,但我看到dropbox提供商与包括BB hub在内的所有应用程序一起工作

更糟糕的是:)例如,dropbox似乎可以在下载时显示自己的UI

你知道怎么做吗


请注意,我多次查看文档和几个示例,但仍然无法让提供商使用所有应用程序,我知道一些应用程序可能使用不当,但dropbox证明可以满足所有应用程序的要求。您的Gmail问题很可能来自ContentProvider生命周期

ContentProvider实际上非常类似于通常从
服务#onBind
返回的。但客户端每次发出请求时,都会通过ContentResolver间接获取应用程序,而不是绑定到您的应用程序。通常没有明确的解除绑定,在每个IPC请求完成后,Android系统会在短时间内缓存提供者

不幸的是,隐式ContentProvider绑定的隐藏性质意味着无法立即释放提供程序。更糟糕的是,没有办法处理有缺陷的提供者中的错误-如果您的ContentProvider在返回游标或ParcelFileDescriptor之前崩溃,调用的应用程序将立即与您一起崩溃!谷歌显然知道这一点,因此他们创建了另一个API,用于与不受信任的第三方内容提供商进行交互。请注意,ContentProviderClient既包含处理远程异常和处理死亡的方法,也包含显式关闭ContentProvider的方法

现在想象一下假设的Gmail ContentProvider工作流:

ParcelFileDescriptor fd = null;

try (ContentProviderClient c = resolver.acquireUnstableContentProviderClient(...)) {
    fd = c.openFile(...)
} catch (Exception ohThoseBuggyProviders) {
    ...
}

// here ContentProvider is already closed

if (fd != null) {
    // use the received descriptor to create email attachment
    ...
}
但是,如果您的ContentProvider想要活得更长一点,以便在后台线程中从服务器读取文件的其余部分,该怎么办?无论如何,系统都可能会终止您的进程,因为它不知道您是否需要它。你的进程死了,Gmail会出现“断管”错误

这就是为什么不应该创建新线程或使用
ContentProvider#openPipeHelper
(为什么该方法存在?),只需在调用线程中完成所有工作即可


问题第二部分的答案也在于ContentProvider内部。当从调用应用程序的主线程调用您的提供者时,您的代码不会在进程的主线程上执行,而是像往常一样在绑定线程池中执行。但为了让程序员的生活更轻松,安卓采取了几个步骤来降低这一点:

  • 线程的优先级设置为发出调用的线程的优先级(包括从UI线程调用时提升到UI优先级)
  • Android当前从调用应用程序到您的线程的严格模式设置(当应用程序在主线程上进行网络连接时会导致应用程序崩溃)。呼叫完成后,将收集所有严格模式冲突并发送回呼叫应用程序
  • 即使ContentProvider操作是在绑定池中执行的,它们的行为几乎就像进程之间没有界限一样——包括当有人试图从UI线程下载文件时发生的错误

    您应该能够通过使用摆脱讨厌的“帮助”,但如果所涉及的文件太大(在调用过程中仍然可能发生ANR),则这样做行不通。而不是从
    openDocument
    a下载文件到管道返回


    为什么Dropbox没有遇到这个问题?因为Dropbox核心是用C++编写的,而Android严格模式是目前java唯一的构造,它不会钩住到本机代码中。如果您使用C库调用在主线程中写入磁盘或从网络下载,您的应用程序将不会收到任何影响(除了ANR,它在UI线程上独立于严格模式触发)。

    尝试
    ContentProvider\openPipeHelper
    ?如果您不想使用openPipeHelper,则可以更轻松地发布
    TransferThread
    code“但是,如果您的ContentProvider想要活得更长一点,以便在后台线程中从服务器读取文件的其余部分,该怎么办?”?无论如何,系统都可能会终止您的进程,因为它不知道您是否需要它。您的进程死亡“那么您是说您不能在更长时间内使用
    CP#query
    方法返回的
    游标,因为承载该CP的进程将被终止?如果不是,它将不会被终止),返回的
    Cursor
    PFD
    之间的区别是什么?@pskink对于其中一个,来自ContentProvider的Cursor,是。ParcelFileDescriptor是,它除了本机描述符之外不包含任何内容(并且,可选地,还包含另一个用于传递元数据的描述符)@pskink我不是说,这是唯一可能的解释,只是最简单的解释。在没有安卓框架开发人员的保证/文档的情况下,我将假设最坏的情况。
    PFD
    不仅仅是简单的
    int
    FD
    ,请参见
    Parcel#writeFileDescriptor
    Parcel#readFileDescriptor
    这些方法是本机方法,在传递
    int
    FD
    的过程中,它们更像是将
    FD
    从一个进程复制到另一个进程,并确保在连接断开时源进程不会终止active@pskink描述符不能只在