我正在我的应用程序中实现新的Storage Access Framework API。除了一个小细节,一切似乎都运行良好。当我使用文档选择器从自己的应用程序(例如,从应用程序内的其他帐户)打开文件时,在主线程上调用openDocument
实现上的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
。仅当我尝试从自己的应用程序(但从另一个帐户,因此从另一个ROOT)中选择文件时,才会发生这种情况。
但是,当我尝试在Google云端硬盘上执行相同的操作(即启动应用程序,然后使用其自己的选择器来选择文件)时,它似乎能够通过网络下载文件而不会导致应用程序崩溃。
请注意,您不应在UI线程上执行此操作。做它背景,使用AsyncTask。
SMB DocumentsProvider由Google启动,但从未完成。查看其源代码,尤其是此文件repo,我们发现Google对pre-O设备使用了管道和读取或写入任务的组合,而对于较新的Android版本则使用了一些奇怪的mClient.openProxyFile() 。为了了解底层机制,有必要进一步调查SMB客户端源代码。