diff --git a/lottie/src/main/java/com/airbnb/lottie/utils/Utils.java b/lottie/src/main/java/com/airbnb/lottie/utils/Utils.java index 0ad4b89b84..8c0abd85b9 100644 --- a/lottie/src/main/java/com/airbnb/lottie/utils/Utils.java +++ b/lottie/src/main/java/com/airbnb/lottie/utils/Utils.java @@ -34,10 +34,37 @@ public final class Utils { public static final int SECOND_IN_NANOS = 1000000000; - private static final PathMeasure pathMeasure = new PathMeasure(); - private static final Path tempPath = new Path(); - private static final Path tempPath2 = new Path(); - private static final float[] points = new float[4]; + /** + * Wrap in Local Thread is necessary for prevent race condition in multi-threaded mode + */ + private static final ThreadLocal threadLocalPathMeasure = new ThreadLocal() { + @Override + protected PathMeasure initialValue() { + return new PathMeasure(); + } + }; + + private static final ThreadLocal threadLocalTempPath = new ThreadLocal() { + @Override + protected Path initialValue() { + return new Path(); + } + }; + + private static final ThreadLocal threadLocalTempPath2 = new ThreadLocal() { + @Override + protected Path initialValue() { + return new Path(); + } + }; + + private static final ThreadLocal threadLocalPoints = new ThreadLocal() { + @Override + protected float[] initialValue() { + return new float[4]; + } + }; + private static final float INV_SQRT_2 = (float) (Math.sqrt(2) / 2.0); private static float dpScale = -1; @@ -71,6 +98,8 @@ public static void closeQuietly(Closeable closeable) { } public static float getScale(Matrix matrix) { + final float[] points = threadLocalPoints.get(); + points[0] = 0; points[1] = 0; // Use 1/sqrt(2) so that the hypotenuse is of length 1. @@ -84,6 +113,8 @@ public static float getScale(Matrix matrix) { } public static boolean hasZeroScaleAxis(Matrix matrix) { + final float[] points = threadLocalPoints.get(); + points[0] = 0; points[1] = 0; // Random numbers. The only way these should map to the same thing as 0,0 is if the scale is 0. @@ -109,6 +140,10 @@ public static void applyTrimPathIfNeeded(Path path, @Nullable TrimPathContent tr public static void applyTrimPathIfNeeded( Path path, float startValue, float endValue, float offsetValue) { L.beginSection("applyTrimPathIfNeeded"); + final PathMeasure pathMeasure = threadLocalPathMeasure.get(); + final Path tempPath = threadLocalTempPath.get(); + final Path tempPath2 = threadLocalTempPath2.get(); + pathMeasure.setPath(path, false); float length = pathMeasure.getLength();