Creates a task that completes when all of the provided tasks are complete.
(Collection<? extends Task<?>> tasks)
| 252 | * Creates a task that completes when all of the provided tasks are complete. |
| 253 | */ |
| 254 | public static Task<Void> whenAll(Collection<? extends Task<?>> tasks) { |
| 255 | if (tasks.size() == 0) { |
| 256 | return Task.forResult(null); |
| 257 | } |
| 258 | |
| 259 | final Task<Void>.TaskCompletionSource allFinished = Task.<Void> create(); |
| 260 | final ArrayList<Exception> errors = new ArrayList<Exception>(); |
| 261 | final Object errorLock = new Object(); |
| 262 | final AtomicInteger count = new AtomicInteger(tasks.size()); |
| 263 | final AtomicBoolean isCancelled = new AtomicBoolean(false); |
| 264 | |
| 265 | for (Task<?> task : tasks) { |
| 266 | @SuppressWarnings("unchecked") |
| 267 | Task<Object> t = (Task<Object>) task; |
| 268 | t.continueWith(new Continuation<Object, Void>() { |
| 269 | @Override |
| 270 | public Void then(Task<Object> task) { |
| 271 | if (task.isFaulted()) { |
| 272 | synchronized (errorLock) { |
| 273 | errors.add(task.getError()); |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | if (task.isCancelled()) { |
| 278 | isCancelled.set(true); |
| 279 | } |
| 280 | |
| 281 | if (count.decrementAndGet() == 0) { |
| 282 | if (errors.size() != 0) { |
| 283 | if (errors.size() == 1) { |
| 284 | allFinished.setError(errors.get(0)); |
| 285 | } else { |
| 286 | allFinished.setError(new AggregateException(errors)); |
| 287 | } |
| 288 | } else if (isCancelled.get()) { |
| 289 | allFinished.setCancelled(); |
| 290 | } else { |
| 291 | allFinished.setResult(null); |
| 292 | } |
| 293 | } |
| 294 | return null; |
| 295 | } |
| 296 | }); |
| 297 | } |
| 298 | |
| 299 | return allFinished.getTask(); |
| 300 | } |
| 301 | |
| 302 | /** |
| 303 | * Continues a task with the equivalent of a Task-based while loop, where the body of the loop is |