Fix asyncUpdates for Nougat and below
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
index 5e9050e..8234e74 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
@@ -16,6 +16,8 @@
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
@@ -83,6 +85,13 @@
     RESUME,
   }
 
+  /**
+   * Prior to Oreo, you could only call invalidateDrawable() from the main thread.
+   * This means that when async updates are enabled, we must post the invalidate call to the main thread.
+   * Newer devices can call invalidate directly from whatever thread asyncUpdates runs on.
+   */
+  private static final boolean invalidateSelfOnMainThread = Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1;
+
   private LottieComposition composition;
   private final LottieValueAnimator animator = new LottieValueAnimator();
 
@@ -146,6 +155,13 @@
   private Matrix softwareRenderingOriginalCanvasMatrix;
   private Matrix softwareRenderingOriginalCanvasMatrixInverse;
 
+  /**
+   * True if the drawable has not been drawn since the last invalidateSelf.
+   * We can do this to prevent things like bounds from getting recalculated
+   * many times.
+   */
+  private boolean isDirty = false;
+
   /** Use the getter so that it can fall back to {@link L#getDefaultAsyncUpdates()}. */
   @Nullable private AsyncUpdates asyncUpdates;
   private final ValueAnimator.AnimatorUpdateListener progressUpdateListener = animation -> {
@@ -181,6 +197,9 @@
    */
   private static final Executor setProgressExecutor = new ThreadPoolExecutor(0, 2, 35, TimeUnit.MILLISECONDS,
       new LinkedBlockingQueue<>(), new LottieThreadFactory());
+  private Handler mainThreadHandler;
+  private Runnable invalidateSelfRunnable;
+
   private final Runnable updateProgressRunnable = () -> {
     CompositionLayer compositionLayer = this.compositionLayer;
     if (compositionLayer == null) {
@@ -189,6 +208,19 @@
     try {
       setProgressDrawLock.acquire();
       compositionLayer.setProgress(animator.getAnimatedValueAbsolute());
+      // Refer to invalidateSelfOnMainThread for more info.
+      if (invalidateSelfOnMainThread && isDirty) {
+        if (mainThreadHandler == null) {
+          mainThreadHandler = new Handler(Looper.getMainLooper());
+          invalidateSelfRunnable = () -> {
+            final Callback callback = getCallback();
+            if (callback != null) {
+              callback.invalidateDrawable(this);
+            }
+          };
+        }
+        mainThreadHandler.post(invalidateSelfRunnable);
+      }
     } catch (InterruptedException e) {
       // Do nothing.
     } finally {
@@ -198,13 +230,6 @@
   private float lastDrawnProgress = -Float.MAX_VALUE;
   private static final float MAX_DELTA_MS_ASYNC_SET_PROGRESS = 3 / 60f * 1000;
 
-  /**
-   * True if the drawable has not been drawn since the last invalidateSelf.
-   * We can do this to prevent things like bounds from getting recalculated
-   * many times.
-   */
-  private boolean isDirty = false;
-
   @IntDef({RESTART, REVERSE})
   @Retention(RetentionPolicy.SOURCE)
   public @interface RepeatMode {
@@ -561,6 +586,11 @@
       return;
     }
     isDirty = true;
+
+    // Refer to invalidateSelfOnMainThread for more info.
+    if (invalidateSelfOnMainThread && Looper.getMainLooper() != Looper.myLooper()) {
+      return;
+    }
     final Callback callback = getCallback();
     if (callback != null) {
       callback.invalidateDrawable(this);