Always use original context (Activity) when obtaining cache key and resource stream to correctly load and handle raw-night resources when the dark mode is on (#1361)
Application context isn't reliable source of information about dark mode (uiMode is UI_MODE_NIGHT_NO when the dark mode is on - Activity carries the correct information) and can incorrectly return default resource instead of the -night variant.
Fixes #1305
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java b/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java
index 2b4a09f..f297279 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java
@@ -18,6 +18,7 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
@@ -128,14 +129,19 @@
* 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.
*/
public static LottieTask<LottieComposition> fromRawRes(Context context, @RawRes final int rawRes) {
// 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>>() {
@Override
public LottieResult<LottieComposition> call() {
- return fromRawResSync(appContext, rawRes);
+ @Nullable Context originalContext = contextRef.get();
+ Context context = originalContext != null ? originalContext : appContext;
+ return fromRawResSync(context, rawRes);
}
});
}
@@ -144,6 +150,8 @@
* 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.
*/
@WorkerThread
public static LottieResult<LottieComposition> fromRawResSync(Context context, @RawRes int rawRes) {
@@ -270,7 +278,9 @@
com.airbnb.lottie.parser.moshi.JsonReader reader, @Nullable String cacheKey, boolean close) {
try {
LottieComposition composition = LottieCompositionMoshiParser.parse(reader);
- LottieCompositionCache.getInstance().put(cacheKey, composition);
+ if (cacheKey != null) {
+ LottieCompositionCache.getInstance().put(cacheKey, composition);
+ }
return new LottieResult<>(composition);
} catch (Exception e) {
return new LottieResult<>(e);
@@ -352,7 +362,9 @@
}
}
- LottieCompositionCache.getInstance().put(cacheKey, composition);
+ if (cacheKey != null) {
+ LottieCompositionCache.getInstance().put(cacheKey, composition);
+ }
return new LottieResult<>(composition);
}
@@ -390,9 +402,6 @@
task.addListener(new LottieListener<LottieComposition>() {
@Override
public void onResult(LottieComposition result) {
- if (cacheKey != null) {
- LottieCompositionCache.getInstance().put(cacheKey, result);
- }
taskCache.remove(cacheKey);
}
});