Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes flickering when the same URL is set to the LottieAnimationView #2328

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
Expand Down Expand Up @@ -90,7 +91,7 @@ public WeakSuccessListener(LottieAnimationView target) {
if (targetView == null) {
return;
}
targetView.setComposition(result);
targetView.setCompositionInternal(result);
}
}

Expand Down Expand Up @@ -123,6 +124,7 @@ public WeakFailureListener(LottieAnimationView target) {

private final LottieDrawable lottieDrawable = new LottieDrawable();
private String animationName;
private String animationUrl;
private @RawRes int animationResId;

/**
Expand Down Expand Up @@ -457,6 +459,7 @@ public void setOutlineMasksAndMattes(boolean outline) {
public void setAnimation(@RawRes final int rawRes) {
this.animationResId = rawRes;
animationName = null;
animationUrl = null;
setCompositionTask(fromRawRes(rawRes));
}

Expand All @@ -474,6 +477,7 @@ private LottieTask<LottieComposition> fromRawRes(@RawRes final int rawRes) {
public void setAnimation(final String assetName) {
this.animationName = assetName;
animationResId = 0;
animationUrl = null;
setCompositionTask(fromAssets(assetName));
}

Expand Down Expand Up @@ -514,6 +518,7 @@ public void setAnimationFromJson(String jsonString, @Nullable String cacheKey) {
* Auto-closes the stream.
*/
public void setAnimation(InputStream stream, @Nullable String cacheKey) {
animationUrl = null;
setCompositionTask(LottieCompositionFactory.fromJsonInputStream(stream, cacheKey));
}

Expand All @@ -532,6 +537,10 @@ public void setAnimation(InputStream stream, @Nullable String cacheKey) {
* @see Lottie#initialize(LottieConfig)
*/
public void setAnimationFromUrl(String url) {
if (Objects.equals(animationUrl, url)) {
return;
}
animationUrl = url;
LottieTask<LottieComposition> task = cacheComposition ?
LottieCompositionFactory.fromUrl(getContext(), url) : LottieCompositionFactory.fromUrl(getContext(), url, null);
setCompositionTask(task);
Expand All @@ -552,6 +561,10 @@ public void setAnimationFromUrl(String url) {
* @see Lottie#initialize(LottieConfig)
*/
public void setAnimationFromUrl(String url, @Nullable String cacheKey) {
if (Objects.equals(animationUrl, url)) {
return;
}
animationUrl = url;
LottieTask<LottieComposition> task = LottieCompositionFactory.fromUrl(getContext(), url, cacheKey);
setCompositionTask(task);
}
Expand Down Expand Up @@ -608,6 +621,11 @@ private void cancelLoaderTask() {
* using {@link R.attr#lottie_cacheComposition}.
*/
public void setComposition(@NonNull LottieComposition composition) {
animationUrl = null;
setCompositionInternal(composition);
}

private void setCompositionInternal(@NonNull LottieComposition composition) {
if (L.DBG) {
Log.v(TAG, "Set Composition \n" + composition);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import android.graphics.drawable.ColorDrawable
import androidx.fragment.app.Fragment
import androidx.fragment.app.testing.launchFragmentInContainer
import androidx.lifecycle.Lifecycle
import androidx.test.espresso.Espresso.onIdle
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
Expand All @@ -14,7 +16,10 @@ import androidx.test.filters.LargeTest
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieCompositionFactory
import com.airbnb.lottie.LottieDrawable
import com.airbnb.lottie.model.LottieCompositionCache
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
Expand Down Expand Up @@ -62,4 +67,38 @@ class LottieAnimationViewTest {
assertFalse(view.isAnimating)
}
}

@Test
fun testDoesNotLoadSameUrlTwice() {
val url = "https://raw.githubusercontent.com/airbnb/lottie-android/master/sample/src/main/res/raw/heart.json"
val cacheKey = "url_${url}"

val idlingResource = LottieIdlingResource()
IdlingRegistry.getInstance().register(idlingResource)

class TestFragment : Fragment(R.layout.lottie_activity_main)

val scenario = launchFragmentInContainer<TestFragment>()
scenario.moveToState(Lifecycle.State.RESUMED)
scenario.onFragment { fragment ->
val view = fragment.requireView().findViewById<LottieAnimationView>(R.id.animation_view)
view.setAnimationFromUrl(url)
}

onIdle()
assertNotNull(LottieCompositionCache.getInstance()[cacheKey])
LottieCompositionCache.getInstance().clear()

scenario.onFragment { fragment ->
val view = fragment.requireView().findViewById<LottieAnimationView>(R.id.animation_view)
view.setAnimationFromUrl(url)
}

// The second call to setAnimationFromUrl() using the same url should avoid reloading the composition
// and thus the underlying cache would not have been re-populated.
onIdle()
assertNull(LottieCompositionCache.getInstance()[cacheKey])

IdlingRegistry.getInstance().unregister(idlingResource)
}
}