diff options
author | Gabriel Peal <gpeal@users.noreply.github.com> | 2019-11-30 14:47:35 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-11-30 14:47:35 -0800 |
commit | ee942249214dd6bb1540b746ca0b678a6382b5ee (patch) | |
tree | 15f355f7a61e4d2f32b1d5ccba34a7e7764599d1 | |
parent | 8d676e1f08a99d18e1d09fa347435e3ff476c27c (diff) | |
download | lottie-ee942249214dd6bb1540b746ca0b678a6382b5ee.tar.gz |
Add the ability to set custom cache keys or set non cache key (#1450)
Fixes #1289
4 files changed, 122 insertions, 26 deletions
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerViewModel.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerViewModel.kt index dac6429d..46e414e9 100644 --- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerViewModel.kt +++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerViewModel.kt @@ -40,9 +40,9 @@ class PlayerViewModel( val url = args.url ?: args.animationData?.lottieLink when { - url != null -> LottieCompositionFactory.fromUrl(application, url) + url != null -> LottieCompositionFactory.fromUrl(application, url, null) args.fileUri != null -> taskForUri(args.fileUri) - args.asset != null -> LottieCompositionFactory.fromAsset(application, args.asset) + args.asset != null -> LottieCompositionFactory.fromAsset(application, args.asset, null) else -> throw IllegalArgumentException("Don't know how to fetch animation for $args") } .addListener { @@ -64,7 +64,7 @@ class PlayerViewModel( return LottieTask { throw e } } - return LottieCompositionFactory.fromJsonInputStream(fis, uri.toString()) + return LottieCompositionFactory.fromJsonInputStream(fis, null) } fun toggleRenderGraphVisible() = setState { copy(renderGraphVisible = !renderGraphVisible) } diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java b/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java index 82f4a647..ed780c1e 100644 --- a/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java +++ b/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java @@ -101,6 +101,7 @@ import static com.airbnb.lottie.RenderMode.HARDWARE; private boolean wasAnimatingWhenNotShown = false; private boolean wasAnimatingWhenDetached = false; private boolean autoPlay = false; + private boolean cacheComposition = true; private RenderMode renderMode = RenderMode.AUTOMATIC; private Set<LottieOnCompositionLoadedListener> lottieOnCompositionLoadedListeners = new HashSet<>(); /** @@ -134,6 +135,7 @@ import static com.airbnb.lottie.RenderMode.HARDWARE; private void init(@Nullable AttributeSet attrs) { TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.LottieAnimationView); if (!isInEditMode()) { + cacheComposition = ta.getBoolean(R.styleable.LottieAnimationView_lottie_cacheComposition, true); boolean hasRawRes = ta.hasValue(R.styleable.LottieAnimationView_lottie_rawRes); boolean hasFileName = ta.hasValue(R.styleable.LottieAnimationView_lottie_fileName); boolean hasUrl = ta.hasValue(R.styleable.LottieAnimationView_lottie_url); @@ -349,19 +351,35 @@ import static com.airbnb.lottie.RenderMode.HARDWARE; } /** + * If set to true, all future compositions that are set will be cached so that they don't need to be parsed + * next time they are loaded. This won't apply to compositions that have already been loaded. + * + * Defaults to true. + * + * {@link R.attr#lottie_cacheComposition} + */ + public void setCacheComposition(boolean cacheComposition) { + this.cacheComposition = cacheComposition; + } + + /** * Sets the animation from a file in the raw directory. * This will load and deserialize the file asynchronously. */ public void setAnimation(@RawRes final int rawRes) { this.animationResId = rawRes; animationName = null; - setCompositionTask(LottieCompositionFactory.fromRawRes(getContext(), rawRes)); + LottieTask<LottieComposition> task = cacheComposition ? + LottieCompositionFactory.fromRawRes(getContext(), rawRes) : LottieCompositionFactory.fromRawRes(getContext(), rawRes, null); + setCompositionTask(task); } public void setAnimation(final String assetName) { this.animationName = assetName; animationResId = 0; - setCompositionTask(LottieCompositionFactory.fromAsset(getContext(), assetName)); + LottieTask<LottieComposition> task = cacheComposition ? + LottieCompositionFactory.fromAsset(getContext(), assetName) : LottieCompositionFactory.fromAsset(getContext(), assetName, null); + setCompositionTask(task); } /** @@ -401,7 +419,9 @@ import static com.airbnb.lottie.RenderMode.HARDWARE; * can be accessed immediately for subsequent requests. If the file does not parse to a composition, the temporary file will be deleted. */ public void setAnimationFromUrl(String url) { - setCompositionTask(LottieCompositionFactory.fromUrl(getContext(), url)); + LottieTask<LottieComposition> task = cacheComposition ? + LottieCompositionFactory.fromUrl(getContext(), url) : LottieCompositionFactory.fromUrl(getContext(), url, null); + setCompositionTask(task); } /** diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java b/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java index f2972796..a1d394fc 100644 --- a/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java +++ b/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java @@ -65,10 +65,20 @@ public class LottieCompositionFactory { * Fetch an animation from an http url. Once it is downloaded once, Lottie will cache the file to disk for * future use. Because of this, you may call `fromUrl` ahead of time to warm the cache if you think you * might need an animation in the future. + * + * To skip the cache, add null as a third parameter. */ public static LottieTask<LottieComposition> fromUrl(final Context context, final String url) { - String urlCacheKey = "url_" + url; - return cache(urlCacheKey, new Callable<LottieResult<LottieComposition>>() { + return fromUrl(context, url, "url_" + url); + } + + /** + * Fetch an animation from an http url. Once it is downloaded once, Lottie will cache the file to disk for + * future use. Because of this, you may call `fromUrl` ahead of time to warm the cache if you think you + * might need an animation in the future. + */ + public static LottieTask<LottieComposition> fromUrl(final Context context, final String url, @Nullable String cacheKey) { + return cache(cacheKey, new Callable<LottieResult<LottieComposition>>() { @Override public LottieResult<LottieComposition> call() { return NetworkFetcher.fetchSync(context, url); @@ -91,15 +101,31 @@ public class LottieCompositionFactory { * The asset file name will be used as a cache key so future usages won't have to parse the json again. * However, if your animation has images, you may package the json and images as a single flattened zip file in assets. * + * To skip the cache, add null as a third parameter. + * * @see #fromZipStream(ZipInputStream, String) */ public static LottieTask<LottieComposition> fromAsset(Context context, final String fileName) { + String cacheKey = "asset_" + fileName; + return fromAsset(context, fileName, cacheKey); + } + + /** + * Parse an animation from src/main/assets. It is recommended to use {@link #fromRawRes(Context, int)} instead. + * The asset file name will be used as a cache key so future usages won't have to parse the json again. + * However, if your animation has images, you may package the json and images as a single flattened zip file in assets. + * + * Pass null as the cache key to skip the cache. + * + * @see #fromZipStream(ZipInputStream, String) + */ + 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(fileName, new Callable<LottieResult<LottieComposition>>() { + return cache(cacheKey, new Callable<LottieResult<LottieComposition>>() { @Override public LottieResult<LottieComposition> call() { - return fromAssetSync(appContext, fileName); + return fromAssetSync(appContext, fileName, cacheKey); } }); } @@ -109,12 +135,28 @@ public class LottieCompositionFactory { * The asset file name will be used as a cache key so future usages won't have to parse the json again. * However, if your animation has images, you may package the json and images as a single flattened zip file in assets. * + * To skip the cache, add null as a third parameter. + * * @see #fromZipStreamSync(ZipInputStream, String) */ @WorkerThread public static LottieResult<LottieComposition> fromAssetSync(Context context, String fileName) { - try { String cacheKey = "asset_" + fileName; + return fromAssetSync(context, fileName, cacheKey); + } + + /** + * Parse an animation from src/main/assets. It is recommended to use {@link #fromRawRes(Context, int)} instead. + * The asset file name will be used as a cache key so future usages won't have to parse the json again. + * However, if your animation has images, you may package the json and images as a single flattened zip file in assets. + * + * Pass null as the cache key to skip the cache. + * + * @see #fromZipStreamSync(ZipInputStream, String) + */ + @WorkerThread + public static LottieResult<LottieComposition> fromAssetSync(Context context, String fileName, @Nullable String cacheKey) { + try { if (fileName.endsWith(".zip")) { return fromZipStreamSync(new ZipInputStream(context.getAssets().open(fileName)), cacheKey); } @@ -131,12 +173,27 @@ public class LottieCompositionFactory { * The resource id will be used as a cache key so future usages won't parse the json again. * Note: to correctly load dark mode (-night) resources, make sure you pass Activity as a context (instead of e.g. the application context). * The Activity won't be leaked. + * + * To skip the cache, add null as a third parameter. */ public static LottieTask<LottieComposition> fromRawRes(Context context, @RawRes final int rawRes) { + return fromRawRes(context, rawRes, rawResCacheKey(context, rawRes)); + } + + /** + * Parse an animation from raw/res. This is recommended over putting your animation in assets because + * it uses a hard reference to R. + * The resource id will be used as a cache key so future usages won't parse the json again. + * Note: to correctly load dark mode (-night) resources, make sure you pass Activity as a context (instead of e.g. the application context). + * The Activity won't be leaked. + * + * Pass null as the cache key to skip caching. + */ + public static LottieTask<LottieComposition> fromRawRes(Context context, @RawRes final int rawRes, @Nullable String cacheKey) { // Prevent accidentally leaking an Activity. final WeakReference<Context> contextRef = new WeakReference<>(context); final Context appContext = context.getApplicationContext(); - return cache(rawResCacheKey(context, rawRes), new Callable<LottieResult<LottieComposition>>() { + return cache(cacheKey, new Callable<LottieResult<LottieComposition>>() { @Override public LottieResult<LottieComposition> call() { @Nullable Context originalContext = contextRef.get(); @@ -152,11 +209,27 @@ public class LottieCompositionFactory { * The resource id will be used as a cache key so future usages won't parse the json again. * Note: to correctly load dark mode (-night) resources, make sure you pass Activity as a context (instead of e.g. the application context). * The Activity won't be leaked. + * + * To skip the cache, add null as a third parameter. */ @WorkerThread public static LottieResult<LottieComposition> fromRawResSync(Context context, @RawRes int rawRes) { + return fromRawResSync(context, rawRes, rawResCacheKey(context, rawRes)); + } + + /** + * Parse an animation from raw/res. This is recommended over putting your animation in assets because + * it uses a hard reference to R. + * The resource id will be used as a cache key so future usages won't parse the json again. + * Note: to correctly load dark mode (-night) resources, make sure you pass Activity as a context (instead of e.g. the application context). + * The Activity won't be leaked. + * + * Pass null as the cache key to skip caching. + */ + @WorkerThread + public static LottieResult<LottieComposition> fromRawResSync(Context context, @RawRes int rawRes, @Nullable String cacheKey) { try { - return fromJsonInputStreamSync(context.getResources().openRawResource(rawRes), rawResCacheKey(context, rawRes)); + return fromJsonInputStreamSync(context.getResources().openRawResource(rawRes), cacheKey); } catch (Resources.NotFoundException e) { return new LottieResult<>(e); } @@ -399,19 +472,21 @@ public class LottieCompositionFactory { } LottieTask<LottieComposition> task = new LottieTask<>(callable); - task.addListener(new LottieListener<LottieComposition>() { - @Override - public void onResult(LottieComposition result) { - taskCache.remove(cacheKey); - } - }); - task.addFailureListener(new LottieListener<Throwable>() { - @Override - public void onResult(Throwable result) { - taskCache.remove(cacheKey); - } - }); - taskCache.put(cacheKey, task); + if (cacheKey != null) { + task.addListener(new LottieListener<LottieComposition>() { + @Override + public void onResult(LottieComposition result) { + taskCache.remove(cacheKey); + } + }); + task.addFailureListener(new LottieListener<Throwable>() { + @Override + public void onResult(Throwable result) { + taskCache.remove(cacheKey); + } + }); + taskCache.put(cacheKey, task); + } return task; } } diff --git a/lottie/src/main/res/values/attrs.xml b/lottie/src/main/res/values/attrs.xml index 5d51c4a1..41f4c7ae 100644 --- a/lottie/src/main/res/values/attrs.xml +++ b/lottie/src/main/res/values/attrs.xml @@ -18,6 +18,7 @@ <attr name="lottie_colorFilter" format="color" /> <attr name="lottie_scale" format="float" /> <attr name="lottie_speed" format="float" /> + <attr name="lottie_cacheComposition" format="boolean" /> <!-- These values must be kept in sync with the RenderMode enum --> <attr name="lottie_renderMode" format="enum"> <enum name="automatic" value="0" /> |