如何使用synchronized块序列化异步调用

时间:2016-10-15 15:07:01

标签: java android firebase firebase-storage

我在我的后端使用Firebase,而在客户端(Android)方面,我尝试按顺序下载一堆图像。我将迭代器包装在synchronized块中,等待每个图像下载。

private Object mLock = new Object();

private void downloadImages() {
   List<StorageReference> storageReferences = getStorageReferences();

   synchronized (mLock) {
      // Iterate trough all image references 
      for (StorageReference sr : storageReferences) {
         sr.getBytes(ONE_MB_BUFFER).addOnCompleteListener(new OnCompleteListener<byte[]>() {
            @Override
            public void onComplete(Task<byte[]> task) {
               if (task.isSuccessful()) {
                  // Success, image downloaded
               }

               // Notify, that we have downloaded the image
               synchronized (mLock) {
                  mLock.notify();
               }
            }
         });

         // Await until we acquire the lock
         try {
            mLock.wait();
         }
         catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

addOnCompleteListener中的回调未被调用。实际上,整个线程都被锁定了。

还有其他替代方法可以排队下载任务吗?像单线程执行器服务一样?

3 个答案:

答案 0 :(得分:1)

另一种方法是使用BlockingQueue。

总体思路是:

  • 启动一个不断轮询队列的线程,下载给定的图像并重新开始
  • 您将所有网址放入队列
  • 侦听器与线程或每个图像相关联

所需代码更少:

final BlockingQueue<URL> queue = new LinkedBlockingQueue<>();
new Thread(new Runnable() {
    @Override
    public void run() {
        while (true) {
            URL url = queue.poll();
            // Download the image and notify the listener               
        }
    }
}).start();

此线程可以由服务启动,因此它可以继续运行并且不依赖于UI。然后,活动可以绑定服务以与其进行交互。

答案 1 :(得分:0)

我最终将ExecutorServicenewSingleThreadExecutor一起使用。如果您想要其他自定义,例如,超时,您可能需要使用newScheduledThreadPool。您可以创建一个线程池并同时执行多个线程。

public class ImageDownloadService extends IntentService {

   @Override
   protected void onHandleIntent(Intent intent) {
      downloadImages();
   }  

   private void downloadImages() {
      ExecutorService executor = Executors.newSingleThreadExecutor();

      List<StorageReference> storageReferences = getStorageReferences();

      for (StorageReference sr : storageReferences) {
         Future<byte[]> future = executor.submit(new FutureImageResult(sr));

         byte[] data = null;

         try {
            data = future.get();
         } catch (InterruptedException e) {
            e.printStackTrace();
         } catch (ExecutionException e) {
            e.printStackTrace();
         }

         if (data != null && data.length > 0) {
            // Image downloaded successfully
         }
      }
   }   

}

提交给执行者服务的future

public class FutureImageResult implements Callable<byte[]> {

    private StorageReference mStorageReference;

    private boolean mIsFailure;

    public FutureImageResult(StorageReference storageReference) {
        mStorageReference = storageReference;
    }

    @Override
    public byte[] call() throws Exception {
        Task<byte[]> task = mStorageReference.getBytes(1024 * 1024);
        task.addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                mIsFailure = true;
            }
        });

        while (!task.isComplete() || mIsFailure);
        byte[] data = task.getResult();

        return data;
    }
}

答案 2 :(得分:0)

您也可以使用CountDownLatch来锁定您的工作线程,直到操作完成。像这样:

private void downloadImages() {
   List<StorageReference> storageReferences = getStorageReferences();
   CountDownLatch waitForDownload = new CountDownLatch(storageReferences.size());
   // Iterate trough all image references 
   for (StorageReference sr : storageReferences) {
         sr.getBytes(ONE_MB_BUFFER).addOnCompleteListener(new OnCompleteListener<byte[]>() {
            @Override
            public void onComplete(Task<byte[]> task) {
               // Notify, that we have downloaded the image and continue
               waitForDownload.countDown();
            }
         });
   }
   // Lock until we download all images
   waitForDownload.await();
   // Continue with the rest of your serialized work having all images downloaded
   ...
}

参考文献:CountDownLatch javadoc