如何防止主UI线程阻塞?
我正在尝试使用FirebaseAPI上传文档列表。在上传开始之前,我想更新UI并显示进度视图 - 在所有上传完成之前,这将保持可见状态。以下代码阻止主UI线程,并且不立即显示进度视图。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
onBackPressed();
}
if (id == R.id.action_add) {
uploadDocuments();
}
return super.onOptionsItemSelected(item);
}
private void uploadDocuments(){
final ProgressDialog dialog = new ProgressDialog(this);
dialog.setIndeterminate(true);
dialog.setMessage("Uploading Docs");
dialog.show();
final ArrayList<Task<?>> tasks = new ArrayList<>();
for(Uri document: documents){
StorageReference filesRef = mStorageRef.child("files/" + document.toString());
UploadTask uploadTask = filesRef.putFile(document);
uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
StorageMetadata storageMetadata = taskSnapshot.getMetadata();
Uri downloadFileUrl = null;
if (storageMetadata != null){
downloadFileUrl = taskSnapshot.getMetadata().getDownloadUrl();
}
if (downloadFileUrl != null){
downloadFileUrls.add(downloadFileUrl);
Log.d(TAG, "Download Url: " + downloadFileUrl.toString());
}
}
});
tasks.add(uploadTask);
}
Tasks.whenAll(tasks).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "ALL TASKS HAVE BEEN UPLOADED");
dialog.cancel();
}
});
Log.d(TAG, "After Tasks.whenAll");
}
我注意到主要的UI线程在上传“外部”内容时会阻止,即从Google驱动器检索到的文档以及类型为“content://com.google.android.apps.docs.storage/document”的关联uri /...'
当我从'content:// media / external / images / media / ...'上传图片时,这不会发生。
答案 0 :(得分:2)
您的更新明确表示在上传“外部”内容时会发生阻止。我观察了您在上传Google云端硬盘文件时所描述的延迟。我用日志语句将sum
的调用括起来。他们表示,为本地文件创建上传任务所需的时间不到100毫秒,而Google云端硬盘文件则需要多秒。
虽然文件的Firebase上传发生在工作线程上,但显然主线程上会出现一些文件的初始处理。对于Google云端硬盘文件,该处理需要花费相当长的时间。也许有一些网络I / O.
以下代码是如何使用AsyncTask在后台线程中执行上载任务创建的基本示例。这仅作为基本演示提供。完整的实现需要解决诸如允许用户取消长时间运行的上载以及处理导致应用程序重新启动的配置更改等问题。
putFile()
if (id == R.id.action_add) {
//uploadDocuments();
new UploadDocsAsyncTask(this, progressView).execute(documents);
}
答案 1 :(得分:0)
您可以创建一个线程来进行上传,这样就不会在主线程中完成所有操作。这将使您的进度视图不会冻结。