在Android上实现DocumentsProvider for the cloud的问题
我制作了自定义文档提供程序实现,其中文件实际上存储在服务器上 我遵循了文档,因此提供商大部分时间都在工作,但我在某些应用程序中遇到了问题,即: 1) Gmail附加来自我的提供商的文件: 最初是我的公共ParcelFileDescriptor openDocument 是这样的:在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
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内部。当从调用应用程序的主线程调用您的提供者时,您的代码不会在进程的主线程上执行,而是像往常一样在绑定线程池中执行。但为了让程序员的生活更轻松,安卓采取了几个步骤来降低这一点:
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描述符不能只在