Android Firebase上传冻结用户界面

Android Firebase上传冻结用户界面,android,multithreading,firebase,firebase-storage,Android,Multithreading,Firebase,Firebase Storage,如何防止主UI线程阻塞 我正在尝试使用FirebaseAPI上载文档列表。在上传开始之前,我想更新UI并显示一个进度视图——在所有上传完成之前,该视图将一直可见。下面的代码会阻止主UI线程,并且不会立即显示进度视图 @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { onBa

如何防止主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");
}
@覆盖
公共布尔值onOptionsItemSelected(菜单项项){
int id=item.getItemId();
if(id==android.R.id.home){
onBackPressed();
}
if(id==R.id.action\u add){
上传文件();
}
返回super.onOptionsItemSelected(项目);
}
私有void上传文档(){
最终进度对话框=新建进度对话框(本);
对话框。setUndeterminate(true);
dialog.setMessage(“上传文档”);
dialog.show();

最终ArrayList您可以创建一个线程来进行上传,这样就不会在主线程中完成所有操作。这将使您的进度视图不会冻结。

您的更新清楚地表明,上传“外部”时会发生阻塞内容。我观察到您在上载Google Drive文件时所描述的延迟。我用日志语句将调用
putFile()
括起来。它们显示为本地文件创建上载任务所需的时间不到100毫秒,而Google Drive文件需要几秒钟

虽然Firebase上传文件是在工作线程上进行的,但显然在主线程上对文件进行了一些初始处理。对于Google驱动器文件来说,这种处理需要惊人的长时间。可能存在一些网络I/O

下面的代码是如何使用在后台线程中执行上载任务创建的基本示例。这仅作为基本演示提供。完整的实现需要解决允许用户取消长时间运行的上载以及处理导致应用程序重新启动的配置更改等问题

if (id == R.id.action_add) {
    //uploadDocuments();
    new UploadDocsAsyncTask(this, progressView).execute(documents);
}

公共类UploadDocsAsyncTask扩展异步任务{
私有静态最终字符串TAG=“UploadDocsAsyncTask”;
私人最终进度对话框;
私人最终视图;
私有最终存储参考mStorageRef;
公共上载DocSasyncTask(上下文cxt,视图){
mProgView=视图;
mDialog=新进度对话框(cxt);
mDialog.setUndeterminate(true);
mDialog.setMessage(“上传文档”);
mStorageRef=FirebaseStorage.getInstance().getReference();
}
@凌驾
受保护的void onPreExecute(){
super.onPreExecute();
Log.d(标签“预执行”);
//mProgView.setVisibility(View.VISIBLE);
mDialog.show();
}
@凌驾
受保护的ArrayList doInBackground(ArrayList…文档){
最终ArrayList任务=新建ArrayList();
最终ArrayList downloadUrls=新ArrayList();
对于(Uri文档:文档[0]){
StorageReference filesRef=mStorageRef.child(“files/”+document.toString());
Log.d(标记“上传:”+document.toString());
UploadTask UploadTask=filesRef.putFile(文档);
Log.d(标记“已创建上载任务”);
uploadTask.addOnSuccessListener(新的OnSuccessListener(){
@凌驾
成功时公共无效(UploadTask.TaskSnapshot TaskSnapshot){
Log.d(标记“上载成功:+taskSnapshot.getUploadSessionUri());
StorageMetadata-StorageMetadata=taskSnapshot.getMetadata();
//Log.d(标记,storageMetadata.getDownloadUrl().toString());
if(storageMetadata!=null){
Uri downloadFileUrl=taskSnapshot.getMetadata().getDownloadUrl();
Log.d(标记“DownloadUrl=“+downloadFileUrl”);
downloadURL.add(downloadFileUrl);
}
}
});
添加(上传任务);
}
Log.d(标记“创建的所有上载任务”);
试一试{
Log.d(标记“等待…”);
任务。等待(任务。何时(任务));
}捕捉(中断异常e){
e、 printStackTrace();
}捕获(执行例外){
e、 printStackTrace();
}
Log.d(标签“后台处理结束”);
返回下载的URL;
}
@凌驾
受保护的void onPostExecute(ArrayList下载URL){
onPostExecute(下载URL);
Log.d(标记,“Post-Execute:Size=“+downloadUrls.Size());
//TODO:对下载的URL做些什么
//mProgView.setVisibility(View.GONE);
mDialog.cancel();
}
}

任务之后添加一个log语句。whenAll()
语句查看任务创建中是否有什么导致阻塞。还可以在
uploadTask.addOnSuccessListener()中添加一个log语句来监视进度。我添加了日志语句,如您在编辑的问题中所见。logcat显示“D/Activity:在tasks.whenAll之后”和“I/Choreographer:跳过120帧!应用程序可能在其主线程上做了太多工作。”。“我更新后的答案表明这是一个实验。如果这仍然是一个开放的问题,那么您上载了多少文档?这仍然是一个问题。即使我只上载了一个文档。我认为这与文档位置有关。我编辑了这个问题。事实上,我正在onSuccess()中收集下载的URL。”。请查看问题中的更新代码。我只上载了一些文档。即使只上载了一个文档,UI也会显示一些冻结状态…我注意到根据上载的uri有不同的行为。我已编辑了问题。如果您有其他指点,我们非常欢迎:)谢谢!!非常感谢,您有我帮了大忙:)
public class UploadDocsAsyncTask extends AsyncTask<ArrayList<Uri>, Void, ArrayList<Uri>> {
    private static final String TAG = "UploadDocsAsyncTask";

    private final ProgressDialog mDialog;
    private final View mProgView;
    private final StorageReference mStorageRef;

    public UploadDocsAsyncTask(Context cxt, View view) {
        mProgView = view;
        mDialog = new ProgressDialog(cxt);
        mDialog.setIndeterminate(true);
        mDialog.setMessage("Uploading Docs");
        mStorageRef = FirebaseStorage.getInstance().getReference();
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        Log.d(TAG, "Pre-Execute");
        //mProgView.setVisibility(View.VISIBLE);
        mDialog.show();
    }

    @Override
    protected ArrayList<Uri> doInBackground(ArrayList<Uri>... documents) {
        final ArrayList<UploadTask> tasks = new ArrayList<>();
        final ArrayList<Uri> downloadUrls = new ArrayList<>();

        for (Uri document : documents[0]) {
            StorageReference filesRef = mStorageRef.child("files/" + document.toString());
            Log.d(TAG, "Uploading: " + document.toString());
            UploadTask uploadTask = filesRef.putFile(document);
            Log.d(TAG, "Upload task created");
            uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                    Log.d(TAG, "Upload Success: " + taskSnapshot.getUploadSessionUri());
                    StorageMetadata storageMetadata = taskSnapshot.getMetadata();
                    //Log.d(TAG, storageMetadata.getDownloadUrl().toString());
                    if (storageMetadata != null){
                        Uri downloadFileUrl = taskSnapshot.getMetadata().getDownloadUrl();
                        Log.d(TAG, "DownloadUrl= " + downloadFileUrl);
                        downloadUrls.add(downloadFileUrl);
                    }
                }
            });
            tasks.add(uploadTask);
        }

        Log.d(TAG, "All upload tasks created");

        try {
            Log.d(TAG, "Waiting...");
            Tasks.await(Tasks.whenAll(tasks));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        Log.d(TAG, "End of background processing");
        return downloadUrls;
    }

    @Override
    protected void onPostExecute(ArrayList<Uri> downloadUrls) {
        super.onPostExecute(downloadUrls);
        Log.d(TAG, "Post-Execute: Size=" + downloadUrls.size());

        // TODO: do something with the downloadUrls
        //mProgView.setVisibility(View.GONE);
        mDialog.cancel();
    }
}