diff --git a/lottie/src/main/java/com/airbnb/lottie/L.java b/lottie/src/main/java/com/airbnb/lottie/L.java index a27d7da7c8..ae9f92c57c 100644 --- a/lottie/src/main/java/com/airbnb/lottie/L.java +++ b/lottie/src/main/java/com/airbnb/lottie/L.java @@ -74,11 +74,21 @@ private static LottieTrace getTrace() { } public static void setFetcher(LottieNetworkFetcher customFetcher) { + if ((fetcher == null && customFetcher == null) || (fetcher != null && fetcher.equals(customFetcher))) { + return; + } + fetcher = customFetcher; + networkFetcher = null; } public static void setCacheProvider(LottieNetworkCacheProvider customProvider) { + if ((cacheProvider == null && customProvider == null) || (cacheProvider != null && cacheProvider.equals(customProvider))) { + return; + } + cacheProvider = customProvider; + networkCache = null; } @NonNull diff --git a/lottie/src/main/java/com/airbnb/lottie/Lottie.java b/lottie/src/main/java/com/airbnb/lottie/Lottie.java index c585572ac1..816fff71bf 100644 --- a/lottie/src/main/java/com/airbnb/lottie/Lottie.java +++ b/lottie/src/main/java/com/airbnb/lottie/Lottie.java @@ -20,7 +20,6 @@ public static void initialize(@NonNull final LottieConfig lottieConfig) { L.setCacheProvider(lottieConfig.cacheProvider); L.setTraceEnabled(lottieConfig.enableSystraceMarkers); L.setNetworkCacheEnabled(lottieConfig.enableNetworkCache); - L.setNetworkCacheEnabled(lottieConfig.enableNetworkCache); L.setDisablePathInterpolatorCache(lottieConfig.disablePathInterpolatorCache); } } diff --git a/lottie/src/test/java/com/airbnb/lottie/LottieInitializeTest.java b/lottie/src/test/java/com/airbnb/lottie/LottieInitializeTest.java new file mode 100644 index 0000000000..688dd73c00 --- /dev/null +++ b/lottie/src/test/java/com/airbnb/lottie/LottieInitializeTest.java @@ -0,0 +1,128 @@ +package com.airbnb.lottie; + +import static org.junit.Assert.assertNotNull; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.airbnb.lottie.network.LottieFetchResult; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.io.InputStream; +import java.util.Objects; + +public class LottieInitializeTest extends BaseTest { + + @Rule + public final TemporaryFolder temporaryFolder1 = new TemporaryFolder(); + + @Rule + public final TemporaryFolder temporaryFolder2 = new TemporaryFolder(); + + private final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + @Before + public void setExecutor() { + LottieTask.EXECUTOR = Runnable::run; + } + + @Test + public void fetchAfterSecondInitialize() { + initializeLottie(temporaryFolder1); + // Fetching here causes the resource to be cached in temporaryFolder1: + LottieResult result1 = LottieCompositionFactory.fromUrlSync(context, "resources://test1.json"); + assertNotNull(result1.getValue()); + + // Manually delete to simulate the end of a test: + temporaryFolder1.delete(); + + initializeLottie(temporaryFolder2); + // Fetching here fails if L.setCacheProvider doesn't reset both its internal networkFetcher and its internal networkCache, because + // temporaryFolder1 has been deleted: + LottieResult result2 = LottieCompositionFactory.fromUrlSync(context, "resources://test1.json"); + assertNotNull(result2.getValue()); + } + + private void initializeLottie(TemporaryFolder temporaryFolder) { + LottieConfig lottieConfig = new LottieConfig.Builder() + .setNetworkCacheDir(temporaryFolder.getRoot()) + .setNetworkFetcher(url -> { + if (url.startsWith("resources://")) { + InputStream stream = Objects.requireNonNull(getClass().getClassLoader()) + .getResourceAsStream(url.substring("resources://".length())); + if (stream != null) { + return new LottieFetchSuccess(stream); + } + } + + return new LottieFetchFailure("Could not load <$url>"); + }) + .build(); + Lottie.initialize(lottieConfig); + } + + private static class LottieFetchSuccess implements LottieFetchResult { + + @NonNull private final InputStream jsonStream; + + LottieFetchSuccess(@NonNull InputStream jsonStream) { + this.jsonStream = jsonStream; + } + + @Override public boolean isSuccessful() { + return true; + } + + @Override @NonNull public InputStream bodyByteStream() { + return jsonStream; + } + + @Override public String contentType() { + return "application/json"; + } + + @Override @Nullable public String error() { + return null; + } + + @Override public void close() { + // No-op + } + } + + private static class LottieFetchFailure implements LottieFetchResult { + + @NonNull private final String errorMessage; + + LottieFetchFailure(@NonNull String errorMessage) { + this.errorMessage = errorMessage; + } + + @Override public boolean isSuccessful() { + return false; + } + + @Override @NonNull public InputStream bodyByteStream() { + throw new RuntimeException("LottieFetchFailure has no body"); + } + + @Override @Nullable public String contentType() { + return null; + } + + @Override public String error() { + return errorMessage; + } + + @Override public void close() { + // No-op + } + } +} diff --git a/lottie/src/test/resources/test1.json b/lottie/src/test/resources/test1.json new file mode 100644 index 0000000000..95394ce8fb --- /dev/null +++ b/lottie/src/test/resources/test1.json @@ -0,0 +1,116 @@ +{ + "v": "4.11.1", + "fr": 60, + "ip": 0, + "op": 180, + "w": 300, + "h": 300, + "nm": "Comp 1", + "ddd": 0, + "assets": [], + "layers": [ + { + "ddd": 0, + "ind": 1, + "ty": 4, + "nm": "Shape Layer 1", + "sr": 1, + "ks": { + "o": { + "a": 0, + "k": 100, + "ix": 11 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "p": { + "a": 0, + "k": [ + 150, + 150, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100, + 100 + ], + "ix": 6 + } + }, + "ao": 0, + "shapes": [ + { + "ty": "rc", + "d": 1, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 2 + }, + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 4 + }, + "nm": "Rectangle Path 1", + "mn": "ADBE Vector Shape - Rect", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [ + 0.928262987324, + 0, + 0, + 1 + ], + "ix": 4 + }, + "o": { + "a": 0, + "k": 100, + "ix": 5 + }, + "r": 1, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + } + ], + "ip": 0, + "op": 180, + "st": 0, + "bm": 0 + } + ] +}