1

我正在将新的存储访问框架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 Drive 上做同样的事情(即启动应用程序,然后使用它自己的选择器来选择文件)时,它似乎能够通过网络下载文件而不会导致应用程序崩溃。

4

2 回答 2

2

这不是 SAF 客户端的问题。DocumentsProvider不应直接在其 API 方法中进行任何网络操作,否则客户端可能会被系统杀死。不幸的是,我在 Google 的官方 Android 文档中找不到任何有用的提示,但幸运的是,有一个废弃的SMB DocumentsProvider,它是由 Google 启动但从未完成的。查看它的源代码,尤其是这个文件repo可以发现,Google 将管道和读取或写入任务的组合用于 pre-O 设备,以及一些奇怪的 mClient.openProxyFile()用于较新版本的 Android。有必要进一步研究 SMB 客户端源代码以了解底层机制。

于 2020-03-04T22:45:20.593 回答
1

好的,我想通了。诀窍是从 myopenDocument间接调用(通过)。当我调用时,我是从主线程调用它,而主线程又调用了主线程。将此调用移至后台线程解决了该问题。ContentResolverActivityonActivityResultopenInputStream()ContentResolveropenDocument

文档在代码片段的前一段中确实提到了这一点:

请注意,您不应在 UI 线程上执行此操作。使用 AsyncTask 在后台执行此操作。

于 2013-11-25T19:38:22.187 回答