airbnb / lottie-android

Render After Effects animations natively on Android and iOS, Web, and React Native
http://airbnb.io/lottie/
Apache License 2.0
35.02k stars 5.41k forks source link

Unable to handle exception using LottieCompositionFactory java.lang.RuntimeException: Font asset not found fonts/Gotham Rounded.ttf #2200

Closed arpitkushwaha closed 1 year ago

arpitkushwaha commented 1 year ago

Lottie is supported and developed on nights and weekends. Issues from Lottie sponsors will be prioritized.

If you don't use this template, your issue will be closed. Delete this text once completed.

Checklist

  1. My animation doesn't use any unsupported features.
  2. I know what part of my animation doesn't work.
  3. I have created a simplified version of my animation
  4. I have attached the AEP file (as a zip file so it can be attached) that only has the part of the animation that doesn't work.

Describe the bug Hello, I am not able to catch the below exception even after using the addFailureListener of LottieCompositionFactory API. Can you please guide me on how to catch the below and similar exceptions, so that the whole app won't crash? Thanks in advance. I am using the below code for catching the exception.

LottieTask<LottieComposition> lottieCompositionLottieTask = LottieCompositionFactory.fromUrl(getContext(), animationUrl); lottieCompositionLottieTask.addListener(new LottieListener<LottieComposition>() { @Override public void onResult(LottieComposition result) { lottieHomePageBannerAnimationView.setComposition(result); lottieHomePageBannerAnimationView.setRepeatCount(isRepeat ? ValueAnimator.INFINITE : 0); lottieHomePageBannerAnimationView.playAnimation(); } }).addFailureListener(new LottieListener<Throwable>() { @Override public void onResult(Throwable result) { ABUtil.getInstance().setLog("Lottie Exception", result.getMessage()); } });

Below is the stack trace of the crash I am trying to handle.

java.lang.RuntimeException: Font asset not found fonts/Gotham Rounded.ttf
        at android.graphics.Typeface.createFromAsset(Typeface.java:1044)
        at com.airbnb.lottie.manager.FontAssetManager.getFontFamily(FontAssetManager.java:87)
        at com.airbnb.lottie.manager.FontAssetManager.getTypeface(FontAssetManager.java:61)
        at com.airbnb.lottie.LottieDrawable.getTypeface(LottieDrawable.java:977)
        at com.airbnb.lottie.model.layer.TextLayer.drawTextWithFont(TextLayer.java:209)
        at com.airbnb.lottie.model.layer.TextLayer.drawLayer(TextLayer.java:142)
        at com.airbnb.lottie.model.layer.BaseLayer.draw(BaseLayer.java:233)
        at com.airbnb.lottie.model.layer.CompositionLayer.drawLayer(CompositionLayer.java:100)
        at com.airbnb.lottie.model.layer.BaseLayer.draw(BaseLayer.java:233)
        at com.airbnb.lottie.model.layer.CompositionLayer.drawLayer(CompositionLayer.java:100)
        at com.airbnb.lottie.model.layer.BaseLayer.draw(BaseLayer.java:233)
        at com.airbnb.lottie.LottieDrawable.draw(LottieDrawable.java:338)
        at android.widget.ImageView.onDraw(ImageView.java:1442)
        at android.view.View.draw(View.java:22644)
        at android.view.View.buildDrawingCacheImpl(View.java:21916)
        at android.view.View.buildDrawingCache(View.java:21776)
        at com.airbnb.lottie.LottieAnimationView.buildDrawingCache(LottieAnimationView.java:822)
        at android.view.View.draw(View.java:22367)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4528)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4289)
        at android.view.View.updateDisplayListIfDirty(View.java:21510)
        at android.view.View.draw(View.java:22375)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4528)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4289)
        at android.view.View.draw(View.java:22647)
        at android.widget.ScrollView.draw(ScrollView.java:1868)
        at android.view.View.updateDisplayListIfDirty(View.java:21519)
        at android.view.View.draw(View.java:22375)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4528)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4289)
        at android.view.View.draw(View.java:22647)
        at android.view.View.updateDisplayListIfDirty(View.java:21519)
        at android.view.View.draw(View.java:22375)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4528)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.drawChild(CoordinatorLayout.java:1277)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4289)
        at android.view.View.draw(View.java:22647)
        at android.view.View.updateDisplayListIfDirty(View.java:21519)
        at android.view.View.draw(View.java:22375)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4528)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4289)
        at android.view.View.updateDisplayListIfDirty(View.java:21510)
        at android.view.View.draw(View.java:22375)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4528)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4289)
        at android.view.View.updateDisplayListIfDirty(View.java:21510)
        at android.view.View.draw(View.java:22375)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4528)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4289)
        at android.view.View.updateDisplayListIfDirty(View.java:21510)
        at android.view.View.draw(View.java:22375)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4528)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4289)
        at android.view.View.updateDisplayListIfDirty(View.java:21510)
        at android.view.View.draw(View.java:22375)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4528)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.drawChild(CoordinatorLayout.java:1277)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4289)
        at android.view.View.updateDisplayListIfDirty(View.java:21510)
        at android.view.View.draw(View.java:22375)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4528)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4289)
        at android.view.View.updateDisplayListIfDirty(View.java:21510)

What version of Lottie did you test this on? lottieVersion = "3.0.3"

What version of Android did you test this on? Android 12

Steps To Reproduce It is a faulty JSON file (I think so). If we use the JSON file and try to load it using LottieAnimationView and LottieCompositionFactory as I did in the above code. It will reproduce.

Screenshots

gpeal commented 1 year ago

Does fonts/Gotham Rounded.ttf exists in the assets folder in your app? It needs to be there in addition to your animation.

arpitkushwaha commented 1 year ago

Thanks for the reply @gpeal. It does not exist in my assets folder. I am trying to load the Lottie JSON file dynamically, by getting it from the server. It can have any font or design.

I have 2 questions,

  1. So, to achieve the above functionality, I would need to put all the fonts inside the assets folder first, and then it will work ?

  2. Is there any way I can handle the mentioned exception using Lottie failure listener if things go sideways and I don't have the required font in my assets folder?

gpeal commented 1 year ago

Yes, you can set a FontAssetDelegate. You'll get a callback with the font name, family, and style and can return whatever you'd like.

arpitkushwaha commented 1 year ago

Okay Sure. Is there any way to catch the exception if it occurs? The code I mentioned in the issue above was unable to catch it.

gpeal commented 1 year ago

An exception where?

arpitkushwaha commented 1 year ago

This exception : java.lang.RuntimeException: Font asset not found fonts/Gotham Rounded.ttf

I have attached the exception log above. Is there any way to catch it ? I tried the below code but it was unable to catch the exception.

LottieTask<LottieComposition> lottieCompositionLottieTask = LottieCompositionFactory.fromUrl(getContext(), animationUrl); lottieCompositionLottieTask.addListener(new LottieListener<LottieComposition>() { @Override public void onResult(LottieComposition result) { lottieHomePageBannerAnimationView.setComposition(result); lottieHomePageBannerAnimationView.setRepeatCount(isRepeat ? ValueAnimator.INFINITE : 0); lottieHomePageBannerAnimationView.playAnimation(); } }).addFailureListener(new LottieListener<Throwable>() { @Override public void onResult(Throwable result) { ABUtil.getInstance().setLog("Lottie Exception", result.getMessage()); } });

gpeal commented 1 year ago

Did you include the font in assets/fonts/Gotham Rounded.ttf? That file is either packaged with your APK or not and it doesn't make sense to swallow that exception.

arpitkushwaha commented 1 year ago

Actually, my use case is that I have a Lottie view in my app and I want to show different animated banners on that dynamically. So, the Lottie JSON file for these banners is created by the design team and the URL for the JSON is sent through backend API which I parse and show in Lottie view in the app. Now, the issue is that there can be scenarios when the design team uses a font that is not present in the assets folder of the app. In that case, The exception produced would be: java.lang.RuntimeException: Font asset not found fonts/Gotham Rounded.ttf So, I want to catch this exception and hide my Lottie view and the animation, So that the app does not crash. But the above code is not able to catch the exception and the app is crashed. How to catch this exception?

arpitkushwaha commented 1 year ago

And No, I did not include it in my assets folder. I want to handle that scenario.

gpeal commented 1 year ago

If you use the FontAssetDelegate would solve this. Return null from its callback if you don't have the font you need.

arpitkushwaha commented 1 year ago

Got it. Thanks a lot, @gpeal.

If anyone else is facing this issue. Please find below-attached code, it fixed this issue for me ( I am using another font i.e. Font_Bold.ttf if the required font is not present). You can also return null as mentioned by @gpeal.

lottieHomePageBannerAnimationView.setFontAssetDelegate(new FontAssetDelegate() {
                            @Override
                            public Typeface fetchFont(String fontFamily) {
                                return Typeface.createFromAsset(activity.getAssets(), "fonts/Font_Bold.ttf");
                            }
                        });
TomekPnz commented 1 year ago

Hey! We have the same issue (randomly on some samsung device with android 13 - sometimes it's happens and sometimes not) like @arpitkushwaha. We are using setFontAssetDelegate like this: lottieView.setFontAssetDelegate(object: FontAssetDelegate() { override fun fetchFont(fontFamily: String): Typeface { return if(fontFamily == "SOME FONT"){ ResourcesCompact.getFont(requiredContext(), R.font.other_font)!! } else { super.fetchFont(fontFamily) }

error: java.lang.RuntimeException: Font asset not found fonts/SOME FONTttf at android.graphics.Typeface.createFromAsset(Typeface.java:1155) at com.airbnb.lottie.manager.FontAssetManager.getFontFamily(FontAssetManager.java:90) at com.airbnb.lottie.manager.FontAssetManager.getTypeface(FontAssetManager.java:64) at com.airbnb.lottie.LottieDrawable.getTypeface(LottieDrawable.java:1250)

We are using lottie 6.0. Is there any way to handle/catch this exception and manage it on app side (eg replace animation or display something else?) @gpeal ?