lottie-android icon indicating copy to clipboard operation
lottie-android copied to clipboard

Animation using ImageAssetDelegate crashes when recreated

Open cmonfortep opened this issue 2 years ago • 3 comments

Describe the bug We are currently using an animation with placeholders to show some images dynamically.

Images are inside our res folder. The images we load are different depending on some business rules, so we rely on a custom ImageAssetDelegate instead of using image asset folder.

This works great, but we've noticed it crashes in some scenarios, mainly when the fragment/activity is recreated. For example, in our case it crashes when system theme changes between light and dark mode. That recreates the fragment and the animation produces a crash.

This is the stacktrace we see:

java.lang.IllegalStateException: You must set an images folder before loading an image. Set it with LottieComposition#setImagesFolder or LottieDrawable#setImagesFolder
        at com.airbnb.lottie.manager.ImageAssetManager.bitmapForId(ImageAssetManager.java:109)
        at com.airbnb.lottie.LottieDrawable.getBitmapForId(LottieDrawable.java:1203)
        at com.airbnb.lottie.model.layer.ImageLayer.getBitmap(ImageLayer.java:79)
        at com.airbnb.lottie.model.layer.ImageLayer.drawLayer(ImageLayer.java:38)
        at com.airbnb.lottie.model.layer.BaseLayer.draw(BaseLayer.java:250)
        at com.airbnb.lottie.model.layer.CompositionLayer.drawLayer(CompositionLayer.java:128)
        at com.airbnb.lottie.model.layer.BaseLayer.draw(BaseLayer.java:250)
        at com.airbnb.lottie.LottieDrawable.drawDirectlyToCanvas(LottieDrawable.java:1354)
        at com.airbnb.lottie.LottieDrawable.draw(LottieDrawable.java:517)
        at android.widget.ImageView.onDraw(ImageView.java:1451)
        at android.view.View.draw(View.java:22803)
        at android.view.View.updateDisplayListIfDirty(View.java:21663)
        at android.view.View.draw(View.java:22523)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4608)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4361)
        at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:1994)
        at android.view.View.draw(View.java:22806)
        at android.view.View.updateDisplayListIfDirty(View.java:21663)
        at android.view.View.draw(View.java:22523)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4608)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4361)
        at android.view.View.draw(View.java:22806)
        at android.view.View.updateDisplayListIfDirty(View.java:21663)
        at android.view.View.draw(View.java:22523)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4608)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4361)
        at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:1994)
        at android.view.View.draw(View.java:22806)
        at android.view.View.updateDisplayListIfDirty(View.java:21663)
        at android.view.View.draw(View.java:22523)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4608)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4361)
        at android.view.View.draw(View.java:22806)
        at com.google.android.material.appbar.AppBarLayout.draw(AppBarLayout.java:417)
        at android.view.View.updateDisplayListIfDirty(View.java:21663)
        at android.view.View.draw(View.java:22523)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4608)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.drawChild(CoordinatorLayout.java:1277)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4361)
        at android.view.View.updateDisplayListIfDirty(View.java:21654)
        at android.view.View.draw(View.java:22523)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4608)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4361)
        at android.view.View.updateDisplayListIfDirty(View.java:21654)
        at android.view.View.draw(View.java:22523)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4608)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4361)
        at android.view.View.updateDisplayListIfDirty(View.java:21654)
        at android.view.View.draw(View.java:22523)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4608)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4361)
        at android.view.View.updateDisplayListIfDirty(View.java:21654)
        at android.view.View.draw(View.java:22523)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4608)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4361)
        at android.view.View.updateDisplayListIfDirty(View.java:21654)
        at android.view.View.draw(View.java:22523)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4608)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4361)
        at android.view.View.updateDisplayListIfDirty(View.java:21654)
        at android.view.View.draw(View.java:22523)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4608)

My assumption is that assetDelegate is not restored and that fallbacks into trying to obtain the images from the asset folder.

Steps To Reproduce

If necessary I can provide a sandbox apk to reproduce the crash (or use the issue-repro module). Just wanted to check first if this is a known issue or if we are missing something.

cmonfortep avatar Jul 01 '22 14:07 cmonfortep

Can you attach a project that reproduces this?

gpeal avatar Jul 01 '22 16:07 gpeal

There you go: https://github.com/cmonfortep/LottieTest

How to reproduce:

  • Open the app
  • click on Play animation
  • change system theme
  • app crashes

Notice something important: We set the assetDelegate when we know the animation will appear. I've tried to simulate a similar scenario by setting the assetDelegate when you click the "Play animation" button. (see https://github.com/cmonfortep/LottieTest/blob/master/app/src/main/java/com/example/lottietest/TestActivity.kt#L24)

cmonfortep avatar Jul 01 '22 16:07 cmonfortep

Same here. Please update

eviv3k avatar Jul 28 '22 04:07 eviv3k

Lottie saves and restores its instance state. In this case, when the configuration change started, the animation was playing. After night mode changed, LottieAnimationView restored its state which was playing. However, your business logic had not yet set an image delegate, thus causing it to crash.

You can disable the saved instance state behavior with android:saveEnabled="false" on your layout. I just tested it in your sample app and it prevented the crash from happening.

gpeal avatar Nov 26 '22 04:11 gpeal