Android DocumentsProvider:openDocument在主线程上被调用

问题描述 投票:1回答:2

我正在我的应用程序中实现新的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云端硬盘上执行相同的操作(即启动应用程序,然后使用其自己的选择器来选择文件)时,它似乎能够通过网络下载文件而不会导致应用程序崩溃。

android android-4.4-kitkat storage-access-framework
2个回答
2
投票
文档确实在上一段中提到了代码片段:

请注意,您不应在UI线程上执行此操作。做它背景,使用AsyncTask。


0
投票
DocumentsProvider不应直接在其API方法中进行任何网络操作,否则客户端可能会被系统杀死。不幸的是,我在Google的官方Android文档中找不到任何有用的提示,但幸运的是,有一个废弃的

SMB DocumentsProvider由Google启动,但从未完成。查看其源代码,尤其是此文件repo,我们发现Google对pre-O设备使用了管道和读取或写入任务的组合,而对于较新的Android版本则使用了一些奇怪的mClient.openProxyFile() 。为了了解底层机制,有必要进一步调查SMB客户端源代码。

© www.soinside.com 2019 - 2024. All rights reserved.