diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java b/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java index 09c8c02812..4f451fb87e 100644 --- a/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java +++ b/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java @@ -470,6 +470,8 @@ public void setAnimationFromJson(String jsonString, @Nullable String cacheKey) { * <p> * This is particularly useful for animations loaded from the network. You can fetch the * bodymovin json from the network and pass it directly here. + * <p> + * Auto-closes the stream. */ public void setAnimation(InputStream stream, @Nullable String cacheKey) { setCompositionTask(LottieCompositionFactory.fromJsonInputStream(stream, cacheKey)); diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java b/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java index 8532394680..b74bcb1c8c 100644 --- a/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java +++ b/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java @@ -130,7 +130,7 @@ public static LottieTask<LottieComposition> fromUrl(final Context context, final LottieCompositionCache.getInstance().put(cacheKey, result.getValue()); } return result; - }); + }, null); } /** @@ -184,7 +184,7 @@ public static LottieTask<LottieComposition> fromAsset(Context context, final Str public static LottieTask<LottieComposition> fromAsset(Context context, final String fileName, @Nullable final String cacheKey) { // Prevent accidentally leaking an Activity. final Context appContext = context.getApplicationContext(); - return cache(cacheKey, () -> fromAssetSync(appContext, fileName, cacheKey)); + return cache(cacheKey, () -> fromAssetSync(appContext, fileName, cacheKey), null); } /** @@ -254,7 +254,7 @@ public static LottieTask<LottieComposition> fromRawRes(Context context, @RawRes @Nullable Context originalContext = contextRef.get(); Context context1 = originalContext != null ? originalContext : appContext; return fromRawResSync(context1, rawRes, cacheKey); - }); + }, null); } /** @@ -311,7 +311,7 @@ private static boolean isNightMode(Context context) { * @see #fromJsonInputStreamSync(InputStream, String, boolean) */ public static LottieTask<LottieComposition> fromJsonInputStream(final InputStream stream, @Nullable final String cacheKey) { - return cache(cacheKey, () -> fromJsonInputStreamSync(stream, cacheKey)); + return cache(cacheKey, () -> fromJsonInputStreamSync(stream, cacheKey), () -> closeQuietly(stream)); } /** @@ -343,7 +343,7 @@ public static LottieTask<LottieComposition> fromJson(final JSONObject json, @Nul return cache(cacheKey, () -> { //noinspection deprecation return fromJsonSync(json, cacheKey); - }); + }, null); } /** @@ -361,7 +361,7 @@ public static LottieResult<LottieComposition> fromJsonSync(JSONObject json, @Nul * @see #fromJsonStringSync(String, String) */ public static LottieTask<LottieComposition> fromJsonString(final String json, @Nullable final String cacheKey) { - return cache(cacheKey, () -> fromJsonStringSync(json, cacheKey)); + return cache(cacheKey, () -> fromJsonStringSync(json, cacheKey), null); } /** @@ -377,7 +377,7 @@ public static LottieResult<LottieComposition> fromJsonStringSync(String json, @N } public static LottieTask<LottieComposition> fromJsonReader(final JsonReader reader, @Nullable final String cacheKey) { - return cache(cacheKey, () -> fromJsonReaderSync(reader, cacheKey)); + return cache(cacheKey, () -> fromJsonReaderSync(reader, cacheKey), () -> Utils.closeQuietly(reader)); } @@ -417,7 +417,7 @@ public static LottieTask<LottieComposition> fromZipStream(final ZipInputStream i * @see #fromZipStreamSync(Context, ZipInputStream, String) */ public static LottieTask<LottieComposition> fromZipStream(Context context, final ZipInputStream inputStream, @Nullable final String cacheKey) { - return cache(cacheKey, () -> fromZipStreamSync(context, inputStream, cacheKey)); + return cache(cacheKey, () -> fromZipStreamSync(context, inputStream, cacheKey), () -> closeQuietly(inputStream)); } /** @@ -604,17 +604,24 @@ private static LottieImageAsset findImageAssetForFileName(LottieComposition comp * If not, create a new task for the callable. * Then, add the new task to the task cache and set up listeners so it gets cleared when done. */ - private static LottieTask<LottieComposition> cache( - @Nullable final String cacheKey, Callable<LottieResult<LottieComposition>> callable) { + private static LottieTask<LottieComposition> cache(@Nullable final String cacheKey, Callable<LottieResult<LottieComposition>> callable, + @Nullable Runnable onCached) { + LottieTask<LottieComposition> task = null; final LottieComposition cachedComposition = cacheKey == null ? null : LottieCompositionCache.getInstance().get(cacheKey); if (cachedComposition != null) { - return new LottieTask<>(() -> new LottieResult<>(cachedComposition)); + task = new LottieTask<>(() -> new LottieResult<>(cachedComposition)); } if (cacheKey != null && taskCache.containsKey(cacheKey)) { - return taskCache.get(cacheKey); + task = taskCache.get(cacheKey); + } + if (task != null) { + if (onCached != null) { + onCached.run(); + } + return task; } - LottieTask<LottieComposition> task = new LottieTask<>(callable); + task = new LottieTask<>(callable); if (cacheKey != null) { AtomicBoolean resultAlreadyCalled = new AtomicBoolean(false); task.addListener(result -> {