@Override
    protected void done() {
      try {
        if (isCancelled()) {
          // We don't need to notify and listeners if the task is cancelled.
          return;
        }

        try {
          lottieTask.setResult(get());
        } catch (InterruptedException | ExecutionException e) {
          lottieTask.setResult(new LottieResult<>(e));
        }
      } finally {
        // LottieFutureTask can be held in memory for up to 60 seconds after the task is done, which would
        // result in holding on to the associated LottieTask instance and leaking its listeners. To avoid
        // that, we clear our the reference to the LottieTask instance.
        //
        // How is LottieFutureTask held for up to 60 seconds? It's a bug in how the VM cleans up stack
        // local variables. When you have a loop that polls a blocking queue and assigns the result
        // to a local variable, after looping the local variable will still reference the previous value
        // until the queue returns the next result.
        //
        // Executors.newCachedThreadPool() relies on a SynchronousQueue and creates a cached thread pool
        // with a default keep alice of 60 seconds. After a given worker thread runs a task, that thread
        // will wait for up to 60 seconds for a new task to come, and while waiting it's also accidentally
        // keeping a reference to the previous task.
        //
        // See commit d577e728e9bccbafc707af3060ea914caa73c14f in AOSP for how that was fixed for Looper.
        lottieTask = null;
      }
    }
Remove a given task failure listener. The task will continue to execute so you can re-add
a listener if necessary.

@return the task for call chaining.
lottie/src/main/java/com/airbnb/lottie/LottieTask.java