Skip to content

Commit

Permalink
Replaced Strong/WeakRef cache with a LruCache (#861)
Browse files Browse the repository at this point in the history
  • Loading branch information
gpeal authored Jul 26, 2018
1 parent ee8b954 commit 3f9ee24
Show file tree
Hide file tree
Showing 13 changed files with 138 additions and 114 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* Deprecated `LottieComposition.Factory` in favor of LottieCompositionFactory.
* The new factory methods make it easier to catch exceptions by separating out success and
failure handlers. Previously, catching exceptions was impossible and would crash your app.
* InputStreams are now always closed even if you use the old APIs. Please be aware if you were
using this while upgrading.
* [Sample App] Added the ability to load a file from assets.
* Added support for miter limit.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ public void run() {
}

private void runAnimation(final String name) {
Log.d(L.TAG, "Running name");
LottieResult<LottieComposition> result = LottieCompositionFactory.fromAssetSync(context, name);
if (result.getException() != null) throw new IllegalStateException(result.getException());
LottieComposition composition = result.getValue();
Expand Down
Binary file added LottieSample/src/main/assets/Tests/map.zip
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
onFailure(IllegalStateException("Response was unsuccessful."))
} else {
if (response.body()?.contentType() == MediaType.parse("application/zip")) {
handleZipResponse(response.body()!!)
handleZipResponse(response.body()!!, url)
} else {
val string = response.body()?.string()
if (string == null) {
onFailure(IllegalStateException("Response body was null"))
return@OkHttpCallback
}
handleJsonResponse(string)
handleJsonResponse(string, url)
}
}
}
Expand All @@ -83,8 +83,8 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
handler.post { error.value = e }
}

private fun handleJsonResponse(jsonString: String) {
LottieCompositionFactory.fromJsonString(jsonString)
private fun handleJsonResponse(jsonString: String, cacheKey: String) {
LottieCompositionFactory.fromJsonString(jsonString, cacheKey)
.addListener {
this.composition.value = it
}
Expand All @@ -94,8 +94,8 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
}

@SuppressLint("CheckResult")
private fun handleZipResponse(body: ResponseBody) {
LottieCompositionFactory.fromZipStream(ZipInputStream(body.byteStream()))
private fun handleZipResponse(body: ResponseBody, cacheKey: String) {
LottieCompositionFactory.fromZipStream(ZipInputStream(body.byteStream()), cacheKey)
.addListener {
composition.value = it
}
Expand All @@ -119,7 +119,7 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
return
}

LottieCompositionFactory.fromJsonInputStream(fis)
LottieCompositionFactory.fromJsonInputStream(fis, uri.toString())
.addListener {
this.composition.value = it
}
Expand Down
18 changes: 18 additions & 0 deletions gcloud_run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,26 @@ fi
gcloud auth activate-service-account --key-file ${HOME}/.cache/gcloud-service-key.json
gcloud config set project lottie-snapshots

RunTests()
{
gcloud firebase test android run --no-auto-google-login --type instrumentation --device model=Nexus5X,version=26 --app LottieSample/build/outputs/apk/debug/LottieSample-debug.apk --test LottieSample/build/outputs/apk/androidTest/debug/LottieSample-debug-androidTest.apk
result=$?
}

RunTests

if [ "$result" -ne "0" ]; then
# Retry if it fails. Sometimes the tests fail on Firebase with a native error
echo "Firebase tests failed. Trying again."
RunTests
fi

if [ "$result" -ne "0" ]; then
# Retry if it fails. Sometimes the tests fail on Firebase with a native error
echo "Firebase tests failed. Trying again."
RunTests
fi

if [ "$result" -eq "0" ]; then
./post_pr_comment.js
fi
Expand Down
1 change: 1 addition & 0 deletions lottie/src/main/java/com/airbnb/lottie/Cancellable.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.airbnb.lottie;

@Deprecated
public interface Cancellable {
void cancel();
}
74 changes: 40 additions & 34 deletions lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

import java.io.StringReader;
import java.util.List;
import java.util.Set;

/**
* This view will load, deserialize, and display an After Effects animation exported with
Expand All @@ -55,9 +56,10 @@


/**
* Caching strategy for compositions that will be reused frequently.
* Weak or Strong indicates the GC reference strength of the composition in the cache.
* Pleaes migrate to LottieCompositionFactory. It has cleaner APIs and a LruCache built in.
* @see LottieCompositionFactory
*/
@Deprecated
public enum CacheStrategy {
None,
Weak,
Expand Down Expand Up @@ -327,24 +329,20 @@ public boolean getUseHardwareAcceleration() {
}

/**
* Sets the animation from a file in the raw directory.
* This will load and deserialize the file asynchronously.
* <p>
* Will not cache the composition once loaded.
* cacheStrategy is deprecated. Compositions are now cached by default.
*
* @see #setAnimationRawRes(int)
*/
public void setAnimation(@RawRes int animationResId) {
setAnimation(animationResId, defaultCacheStrategy);
@Deprecated
public void setAnimation(@RawRes final int rawRes, final CacheStrategy cacheStrategy) {
setAnimation(rawRes);
}

/**
* Sets the animation from a file in the raw directory.
* This will load and deserialize the file asynchronously.
* <p>
* You may also specify a cache strategy. Specifying {@link CacheStrategy#Strong} will hold a
* strong reference to the composition once it is loaded
* and deserialized. {@link CacheStrategy#Weak} will hold a weak reference to said composition.
*/
public void setAnimation(@RawRes final int rawRes, final CacheStrategy cacheStrategy) {
public void setAnimation(@RawRes final int rawRes) {
this.animationResId = rawRes;
animationName = null;
LottieComposition cachedComposition = LottieCompositionCache.getInstance().getRawRes(rawRes);
Expand All @@ -358,32 +356,24 @@ public void setAnimation(@RawRes final int rawRes, final CacheStrategy cacheStra
compositionTask = LottieCompositionFactory.fromRawRes(getContext(), rawRes)
.addListener(new LottieListener<LottieComposition>() {
@Override public void onResult(LottieComposition composition) {
LottieCompositionCache.getInstance().put(rawRes, composition, cacheStrategy);
LottieCompositionCache.getInstance().put(rawRes, composition);
}
})
.addListener(loadedListener)
.addFailureListener(failureListener);
}

/**
* Sets the animation from a file in the assets directory.
* This will load and deserialize the file asynchronously.
* <p>
* Will not cache the composition once loaded.
* cacheStrategy is deprecated. Compositions are now cached by default.
*
* @see #setAnimationAsset(String)
*/
public void setAnimation(String animationName) {
setAnimation(animationName, defaultCacheStrategy);
@Deprecated
public void setAnimation(String assetName, CacheStrategy cacheStrategy) {
setAnimation(assetName);
}

/**
* Sets the animation from a file in the assets directory.
* This will load and deserialize the file asynchronously if it is not already in the cache.
* <p>
* You may also specify a cache strategy. Specifying {@link CacheStrategy#Strong} will hold a
* strong reference to the composition once it is loaded
* and deserialized. {@link CacheStrategy#Weak} will hold a weak reference to said composition.
*/
public void setAnimation(final String assetName, final CacheStrategy cacheStrategy) {
public void setAnimation(final String assetName) {
this.animationName = assetName;
animationResId = 0;
LottieComposition cachedComposition = LottieCompositionCache.getInstance().get(assetName);
Expand All @@ -397,7 +387,7 @@ public void setAnimation(final String assetName, final CacheStrategy cacheStrate
compositionTask = LottieCompositionFactory.fromAsset(getContext(), assetName)
.addListener(new LottieListener<LottieComposition>() {
@Override public void onResult(LottieComposition composition) {
LottieCompositionCache.getInstance().put(assetName, composition, cacheStrategy);
LottieCompositionCache.getInstance().put(assetName, composition);
}
})
.addListener(loadedListener)
Expand All @@ -416,13 +406,29 @@ public void setAnimation(JSONObject json) {
setAnimation(new JsonReader(new StringReader(json.toString())));
}

/**
* @see #setAnimationFromJson(String, String)
*/
@Deprecated
public void setAnimationFromJson(String jsonString) {
setAnimationFromJson(jsonString, null);
}

/**
* Sets the animation from json string. This is the ideal API to use when loading an animation
* over the network because you can use the raw response body here and a converstion to a
* JSONObject never has to be done.
*/
public void setAnimationFromJson(String jsonString) {
setAnimation(new JsonReader(new StringReader(jsonString)));
public void setAnimationFromJson(String jsonString, @Nullable String cacheKey) {
setAnimation(new JsonReader(new StringReader(jsonString)), cacheKey);
}

/**
* @see #setAnimation(JsonReader, String)
*/
@Deprecated
public void setAnimation(JsonReader reader) {
setAnimation(reader, null);
}

/**
Expand All @@ -432,10 +438,10 @@ public void setAnimationFromJson(String jsonString) {
* This is particularly useful for animations loaded from the network. You can fetch the
* bodymovin json from the network and pass it directly here.
*/
public void setAnimation(JsonReader reader) {
public void setAnimation(JsonReader reader, @Nullable String cacheKey) {
clearComposition();
cancelLoaderTask();
compositionTask = LottieCompositionFactory.fromJsonReader(reader)
compositionTask = LottieCompositionFactory.fromJsonReader(reader, cacheKey)
.addListener(loadedListener)
.addFailureListener(failureListener);
}
Expand Down
21 changes: 13 additions & 8 deletions lottie/src/main/java/com/airbnb/lottie/LottieComposition.java
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public static Cancellable fromRawFile(Context context, @RawRes int resId, OnComp
*/
public static Cancellable fromInputStream(InputStream stream, OnCompositionLoadedListener l) {
ListenerAdapter listener = new ListenerAdapter(l);
LottieCompositionFactory.fromJsonInputStream(stream).addListener(listener);
LottieCompositionFactory.fromJsonInputStream(stream, null).addListener(listener);
return listener;
}

Expand All @@ -192,7 +192,7 @@ public static Cancellable fromInputStream(InputStream stream, OnCompositionLoade
*/
public static Cancellable fromJsonString(String jsonString, OnCompositionLoadedListener l) {
ListenerAdapter listener = new ListenerAdapter(l);
LottieCompositionFactory.fromJsonString(jsonString).addListener(listener);
LottieCompositionFactory.fromJsonString(jsonString, null).addListener(listener);
return listener;
}

Expand All @@ -201,7 +201,7 @@ public static Cancellable fromJsonString(String jsonString, OnCompositionLoadedL
*/
public static Cancellable fromJsonReader(JsonReader reader, OnCompositionLoadedListener l) {
ListenerAdapter listener = new ListenerAdapter(l);
LottieCompositionFactory.fromJsonReader(reader).addListener(listener);
LottieCompositionFactory.fromJsonReader(reader, null).addListener(listener);
return listener;
}

Expand All @@ -220,16 +220,21 @@ public static LottieComposition fromFileSync(Context context, String fileName) {
@Nullable
@WorkerThread
public static LottieComposition fromInputStreamSync(InputStream stream) {
return LottieCompositionFactory.fromJsonInputStreamSync(stream).getValue();
return LottieCompositionFactory.fromJsonInputStreamSync(stream, null).getValue();
}

/**
* This will now auto-close the input stream!
*
* @see LottieCompositionFactory#fromJsonInputStreamSync(InputStream, boolean)
*/
@Nullable
@WorkerThread
public static LottieComposition fromInputStreamSync(InputStream stream, boolean close) {
return LottieCompositionFactory.fromJsonInputStreamSync(stream, close).getValue();
if (close) {
Log.w(L.TAG, "Lottie now auto-closes input stream!");
}
return LottieCompositionFactory.fromJsonInputStreamSync(stream, null).getValue();
}

/**
Expand All @@ -238,7 +243,7 @@ public static LottieComposition fromInputStreamSync(InputStream stream, boolean
@Nullable
@WorkerThread
public static LottieComposition fromJsonSync(@SuppressWarnings("unused") Resources res, JSONObject json) {
return LottieCompositionFactory.fromJsonSync(json).getValue();
return LottieCompositionFactory.fromJsonSync(json, null).getValue();
}

/**
Expand All @@ -247,7 +252,7 @@ public static LottieComposition fromJsonSync(@SuppressWarnings("unused") Resourc
@Nullable
@WorkerThread
public static LottieComposition fromJsonSync(String json) {
return LottieCompositionFactory.fromJsonStringSync(json).getValue();
return LottieCompositionFactory.fromJsonStringSync(json, null).getValue();
}

/**
Expand All @@ -256,7 +261,7 @@ public static LottieComposition fromJsonSync(String json) {
@Nullable
@WorkerThread
public static LottieComposition fromJsonSync(JsonReader reader) throws IOException {
return LottieCompositionFactory.fromJsonReaderSync(reader).getValue();
return LottieCompositionFactory.fromJsonReaderSync(reader, null).getValue();
}

private static final class ListenerAdapter implements LottieListener<LottieComposition>, Cancellable {
Expand Down
Loading

0 comments on commit 3f9ee24

Please sign in to comment.