我正在我的应用程序中实现新的存储访问框架 API。一切似乎都很顺利,除了一个小细节。当我使用文档选择器从我自己的应用程序(例如从应用程序中的不同帐户)打开一个文件时,我的DocumentsProvider实现上的DocumentsProvider将在主线程上被调用。如果请求的文件已在本地缓存,这是很好的,但如果没有缓存,则会发出网络请求,从而导致NetworkInMainThreadException。有趣的是,文档提到“可以在这种方法中进行网络操作来下载文档”。这是一个已知的错误吗?如果是的话,有没有人知道解决这个问题的方法?
下面是启动选择器的代码:
Intent target = new Intent(Intent.ACTION_OPEN_DOCUMENT);
target.setType("*/*");
target.addCategory(Intent.CATEGORY_OPENABLE);
final Intent intent = Intent.createChooser(target, getString(R.string.document_choose));
try {
startActivityForResult(intent, SELECT_FILE_REQUEST_CODE);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}然后,当用户选择了一个文件时,我大致是这样处理openDocument的
@Override
public ParcelFileDescriptor openDocument(final String documentId, String mode,
CancellationSignal signal) throws FileNotFoundException {
final File file = getFileFromId(documentId);
if(!file.exists()) {
// This is where I have problems
if("main".equalsIgnoreCase(Thread.currentThread().getName())) {
throw new FileNotFoundException("File has not been cached locally.");
} else {
downloadFile(app, file, document, folder);
}
}
}注意在主线程上调用的检查。当外部应用程序使用我的应用程序选择一个文件时,这种情况不会发生,因为然后在后台线程上调用openDocument。只有当我尝试从我自己的应用程序中选择一个文件时(但是从一个不同的帐户,因此是一个不同的根),这种情况才会发生。
然而,当我尝试在Google上做同样的事情(即启动应用程序,然后使用自己的选择器选择一个文件)时,它似乎能够在不破坏应用程序的情况下通过网络下载该文件。
发布于 2013-11-25 19:38:22
好吧我想明白了。诀窍是,openDocument是从我的Activity的onActivityResult中间接调用的(通过ContentResolver)。当我在ContentResolver上调用openInputStream()时,我是从主线程调用它,而主线程则是在主线程上调用openDocument。将这个调用移动到后台线程解决了问题。
在上一段中,文档确实向代码片段提到了这一点:
请注意,不应在UI线程上执行此操作。在后台使用AsyncTask进行操作。
发布于 2020-03-04 22:45:20
这不是苏丹武装部队客户的问题。DocumentsProvider不应该在其API方法中直接执行任何网络操作,否则客户端可能会被系统杀死。不幸的是,我在谷歌的官方安卓文档中找不到任何有用的提示,但幸运的是,有一个被废弃的SMB DocumentsProvider是由谷歌启动但从未完成的。看看它的源代码,特别是这个文件存储库,就会发现Google将管道和读写任务结合在一起用于预O设备,而一些奇怪的mClient.openProxyFile()则用于较新版本的Android。进一步研究SMB客户端源代码对于理解底层机制是必要的。
https://stackoverflow.com/questions/20201412
复制相似问题