5

I have this one fragment that loads tons of data and display it into recyclerView. If I open this fragment directly without waiting for transition completed the transition will become choppy because the thread is throttled by recyclerView update data

So I want to delay this update data until fragment transition completed.

But sadly I have yet to find any way to listen to fragment transition completed so my current approach is to delay the data update for several miliseconds until using Handler() , but I believe this is very hacky and not elegant solution

Handler().postDelayed({
//do something
}, 500)

I need help to know what method should I call to listen to the fragment transition completed . Thank youuu

Fugogugo
  • 4,460
  • 10
  • 36
  • 50

3 Answers3

2

hmm I somehow did it with onCreateAnimation following this answer

override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
    val anim: Animation = AnimationUtils.loadAnimation(activity, nextAnim)
    anim.setAnimationListener(object : Animation.AnimationListener {
        override fun onAnimationStart(animation: Animation?) {}
        override fun onAnimationRepeat(animation: Animation?) {}
        override fun onAnimationEnd(animation: Animation?) {
            if (enter) {
                //load and update recyclerView here
            }
        }
    })
    return anim
}
Fugogugo
  • 4,460
  • 10
  • 36
  • 50
  • I'm not sure I understand this question, but could we use a timer instead of a delay? – shn Apr 13 '21 at 11:20
  • 1
    @Furkan the problem with timer/delay etc is when I change the transition duration it would break and the screen become laggy again. I need to make sure that the transition keeps smooth however I tweak the values – Fugogugo Apr 13 '21 at 14:10
2

Fragments offer two ways of avoiding this problem:

  1. You can avoid starting your transition until your data is loaded by postponing your transition. This ensures that your RecyclerView is already populated with data that can be used for shared element transitions, etc. This is the general recommendation and ensures a smooth transition on all versions of Fragments.

  2. When using Fragment 1.3.0 or higher, your fragment will not reach the resumed state until any transitions or Animators (specifically not Animations) are complete. This allows you to use onResume() as a signal that your transitions are complete.

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • 1
    Hi, Ian! I'm using Fragment `1.3.1` and `onResume()` seems to be called right after `navigate()` is. I also tried using version `1.3.0`, but that didn't work either. – Max May 25 '21 at 18:59
  • So are you using Animators? Animations? Framework Transitions? AndroidX Transitions? If the very last, what version of AndroidX Transitions? Make sure you are using the latest ([Transition 1.4.1](http://developer.android.com/jetpack/androidx/releases/transition#1.4.1)). – ianhanniballake May 25 '21 at 19:13
  • I'm using custom-defined sliding Animations with the Android Navigation Component. – Max May 26 '21 at 05:29
  • 1
    As mentioned very specifically in my answer, Animations are the one exception to the timing of `onResume()` (have you considered using a [Slide Transition](https://developer.android.com/reference/androidx/transition/Slide)?). Postponing works with any time of effect, including Animations, and allows you to fully load your data before starting the Animation. That's why mentioned that approach first :-) – ianhanniballake May 26 '21 at 14:25
  • Thank you for clarifying that :-) – Max May 26 '21 at 16:41
  • What if some actions required to perform right after transitions end? Specifically, I do not need to load data, but need to change visibility of GLSurfaceView? If GL View is visible while transitions still performs - it appears on-top of all view hierarchy and also over the fragment from which exit was performed – A. Petrov Jan 12 '23 at 07:16
0

If you have to use animations, rather than Transitions or Animators, you can extract the animation duration into an integer resource and set the animation duration to it:

<!-- values/durations.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="animation_duration">220</integer>
</resources>

<!-- anim/transition.xml -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false" >
    <alpha android:duration="@integer/animation_duration" android:fromAlpha="0.0" android:toAlpha="1.0" />
</set>

And then retrieve it in your fragment:

val animationDuration = requireContext().resources.getInteger(R.integer.animation_duration)
Handler().postDelayed({
//do something
}, animationDuration)
Max
  • 739
  • 2
  • 8
  • 23