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.04k stars 5.41k forks source link

LottieAnimationView - Memory leak with simple code :( #1916

Closed krzysztofs4d closed 3 years ago

krzysztofs4d commented 3 years ago

Hi Lottie community.

Describe the bug I read whole repository but im stuck with very basic code and leaking LottieAnimationView so any help is greatly appreciated.

I've tried multiple approaches with loading up lottie animation (via xml, via code, open as Fragment, FragmentActivity, AppActivity etc). Nothing seems to help and LottieAnimationView is never removed from heap however container view / activity or activity contains LottieAnimationView is. I've tried setting this also as WeakReference but no luck :(

Maybe im missing something or maybe im doing something wrong :(

I've checked 4.1.0 and 3.7.

Steps To Reproduce Steps to reproduce the behavior:

  1. Open Fragment / FragmentActivity / AppCompatActivity containing LottieAnimationView
  2. disable repeatCount and cacheComposition
  3. Remove / Destroy it
  4. Profile memory, force GC and search for LottieAnimationView
  5. Instance is never deallocated however onDestroyMethod is called and LottieFragment class is deallocated

Fragment Code:

class LottieFragment : Fragment() {
    var lottieAnimationViewRef: WeakReference<LottieAnimationView>? = null

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        super.onCreateView(inflater, container, savedInstanceState)

        lottieAnimationViewRef = WeakReference(LottieAnimationView(requireContext()))
        val lottieAnimationView = lottieAnimationViewRef?.get()

        lottieAnimationView?.repeatCount = 0
        lottieAnimationView?.setAnimation(R.raw.tutu)
        lottieAnimationView?.setCacheComposition(false)
        lottieAnimationView?.layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT)
        lottieAnimationView?.playAnimation()

        return lottieAnimationView
    }

    override fun onDestroy() {
        super.onDestroy()
        // MANUAL DESTROY WHICH SHOULD NOT BE NEEDED AT ALL 
        val lottieAnimationView = lottieAnimationViewRef?.get()
        lottieAnimationView?.cancelAnimation()
        lottieAnimationView?.clearAnimation()
        lottieAnimationView?.removeAllAnimatorListeners()
        lottieAnimationView?.removeAllLottieOnCompositionLoadedListener()
        lottieAnimationViewRef?.clear()
    }
 }

Memory reference seems to be kept in DEFAULT_FAILURE_LISTENER which ive tried to set, clear as well etc.

krzysztofs4d commented 3 years ago

I had to call LottieCompositionFactory.clearCache(requireContext()) during onDestroy method and almost all assets loaded during animation were deallocated.