【问题标题】:Complete AsyncTask only when Firebase Task completes仅在 Firebase 任务完成时完成 AsyncTask
【发布时间】:2018-08-19 23:57:16
【问题描述】:

如何让 AsyncTask 的 doInBackground() 仅在另一个异步方法完成时返回?

在高层次上,活动的目的是允许用户上传评论。评论也可能有图像。现在在我的代码中,我有两个 AsyncTask:ImageCompressionTaskImageUploadTask。基本上,一旦用户选择要上传的图像,就会为每个图像执行ImageCompressionTask。在该任务的onPostExecute() 方法中,ImageUploadTask 被执行。 ImageUploadTask 的目的是上传压缩图片,并使用上述上传图片的下载 URL 更新 Firestore(数据库)。以下是它的代码:

public class ImageUploadTask extends AsyncTask<byte[], Integer, Void> {

    @Override
    protected Void doInBackground(byte[]... bytes) {
        StorageReference ref = App.getFireStorage().getReference();
        ref = ref.child("review_images/" +
                mDestinationId + "/" +
                mExistingReview.getReviewId() + "/" +
                mUploadProgressCount);

        ref.putBytes(bytes[0]).addOnSuccessListener(taskSnapshot -> {
            String url = taskSnapshot.getDownloadUrl().toString();
            mExistingReview.getImages().add(url);

            App.getFirestore().collection("reviews").document(mExistingReview.getReviewId()).set(mExistingReview);

            mUploadProgressCount++;
        });

        return null;
    }
}

但是,问题在于doInBackground() 过早返回。我明白为什么会发生这种情况(因为 ref.putBytes() 方法异步运行)但我希望它等到 ref.putBytes() 完成。我该怎么做?

【问题讨论】:

  • 你看过CountDownLatch吗?这可能有用:docs.oracle.com/javase/7/docs/api/java/util/concurrent/…
  • 你为什么还要使用AsyncTask?您编写的任何代码都不需要在后台线程上运行(这就是putBytes 要求您设置成功侦听器的原因)。
  • @ninge 我以前没有使用过这个,但是查看文档,我是否更正假设这与 Gastón Saillén 提供的解决方案非常相似?
  • @ianhanniballake 没错,我对将网络代码放入ImageCompressionTask 的主线程犹豫不决,因此我这样做了。除了冗余之外,这种方法有什么缺点吗?
  • @NajmSheikh 它应该是一个更简单的解决方案。看我的回答。

标签: android firebase android-asynctask firebase-storage


【解决方案1】:

你能这样检查吗:

 @Override
protected synchronized Void doInBackground(byte[]... bytes) {
    StorageReference ref = App.getFireStorage().getReference();
    ref = ref.child("review_images/" +
            mDestinationId + "/" +
            mExistingReview.getReviewId() + "/" +
            mUploadProgressCount);

    ref.putBytes(bytes[0]).addOnSuccessListener(taskSnapshot -> {
        String url = taskSnapshot.getDownloadUrl().toString();
        mExistingReview.getImages().add(url);

        App.getFirestore().collection("reviews").document(mExistingReview.getReviewId()).set(mExistingReview);

        mUploadProgressCount++;
    });

    return null;
}

【讨论】:

  • 否则你的部分代码是 ref.putBytes() 保持在同步块中,如下所示: synchronized(this){ //如果需要,将你的代码保留在此处并返回 }
【解决方案2】:

我已经用ObservableInteger解决了这个问题

是一个监听值的监听器

private ObservableInteger mObsInt;

 //Listener
        mObsInt = new ObservableInteger();
        mObsInt.set(0);

        mObsInt.setOnIntegerChangeListener(new OnIntegerChangeListener()
        {
            @Override
            public void onIntegerChanged(int newValue)
            {
                if (mObsInt.get()==1)
                    Log.e("Downloads"," mObsInt 1");
                Log.e("Download1"," Finished first process ");
                if (mObsInt.get()==2){
                    Log.e("Downloads"," mObsInt 2");
                    Log.e("Download2"," Finished second process ");
                    mProgressDialog.dismiss();
                    Intent mainIntent = new Intent().setClass(LoginActivity.this, Principal.class);
                    startActivity(mainIntent);
                    finish();
                }
            }
        });

然后就这样做(在进程完成或异步任务之后)

mObsInt.set(mObsInt.get()+1);

所以它会计数,如果第一件事完成 obsInt 将为 1 ,而当第二件事完成时, obsInt 将为 2 ,因此在 obsInt == 2 之后,您可以继续进行您需要的其他活动或流程

编码愉快!

【讨论】:

  • 感谢您的回答!如果我理解正确,那么您基本上是在每一步都增加可观察的 int 。一旦达到一定数量,您就可以完成您需要做的任何事情。如果是这样,如果发生一些错误并且计数器从未达到“成功”值怎么办?你是怎么处理的?
  • 另外,您是否为ObservableInteger 使用了不同的库?与android.databinding 包不同?
  • AndroidStudio自带的ObservableInteger developer.android.com/reference/android/databinding/…
  • 如果它从未到达其中一个计数器,您可以随意处理,因为我需要到达我的应用程序中的每个异步,如果没有进程,我只是再次触发异步,或者给用户显示“稍后再试”的用户界面
【解决方案3】:

这可以通过CountDownLatch来完成:

 public class ImageUploadTask extends AsyncTask<byte[], Integer, Void> {

            @Override
            protected Void doInBackground(byte[]... bytes) {

                // Initialize CountDownLatch
                final CountDownLatch signal = new CountDownLatch(1);

                StorageReference ref = App.getFireStorage().getReference();
                ref = ref.child("review_images/" +
                        mDestinationId + "/" +
                        mExistingReview.getReviewId() + "/" +
                        mUploadProgressCount);

                ref.putBytes(bytes[0]).addOnSuccessListener(taskSnapshot -> {
                    String url = taskSnapshot.getDownloadUrl().toString();
                    mExistingReview.getImages().add(url);

                    App.getFirestore().collection("reviews").document(mExistingReview.getReviewId()).set(mExistingReview);

                    mUploadProgressCount++;

                   // Start count down
                   signal.countDown();
                });

                // Wait for putBytes to return and handle case if
                // threads get interrupted.
                // You can also specify a maximum time to wait before 
                // displaying error to user (ie Try Again)
                try {
                    signal.await(30, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                return null;
            }
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    相关资源
    最近更新 更多