Animation at the beginning of activity skips frames
Asked Answered
T

1

8

I am animating a view in an activity after onGlobalLayoutFinished is called on the view. My animation is skipping ~300 ms worth of frames in the beginning. If I delay the animation by more than ~300ms, it does not skip any frames. What is going on in the activity that is causing this to happen? How can I stop it or how can I listen for when it is finished?

I have created a dead simple app to demonstrate this behavior.

contents of <application> in AndroidManifest.xml:

<activity
    android:name=".main.TestLagActivity"
    android:label="Test Lag Activity">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>

TestLagActivity.java:

public class TestLagActivity extends ActionBarActivity { 
  private View mRedSquareView;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test_lag);

    mRedSquareView = findViewById(R.id.activity_test_lag_redSquareView);

    if (mRedSquareView.getViewTreeObserver() != null) {
      mRedSquareView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        public void onGlobalLayout() {
          mRedSquareView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
          animate();
        }
      });
    }
  }

  private void animate() {
    ObjectAnimator xAnimator = ObjectAnimator.ofFloat(mRedSquareView, "x", 0, 1000);
    xAnimator.setDuration(1000);
    xAnimator.start();
  }
}

activity_test_lag.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent">

  <View
      android:id="@+id/activity_test_lag_redSquareView"
      android:layout_width="50dp"
      android:layout_height="50dp"
      android:background="#FF0000"/>

</FrameLayout>

In this demo, a red square moves from left to right 1000 pixels over 1000 milliseconds. If no delay is set, it skips roughly the first 300 pixels. If a delay is set, it animates smoothly. Please see videos below.

No delay (skips frames): https://www.youtube.com/watch?v=dEwvllhvvN0

400ms delay (does not skip fames): https://www.youtube.com/watch?v=zW0akPhl_9I&feature=youtu.be

Any comments are welcome.

Territory answered 10/2, 2015 at 23:18 Comment(14)
You really need to show your onPause and onSaveInstanceState methods and potentially your view hierarchy. You may have custom logic blocking in onPause before onSaveInstanceState or you may have a custom view that block in onSaveInstanceState.Hola
"onPause and onSaveInstanceState normally happen within 20ms of each other in MainActivity" ... what are you doing different in CreatActivity?Relict
@Hola I should have mentioned the methods are empty, besides the log statements.Territory
@JeffreyBlattman I was referring to the difference when starting a new activity and just turning off the screen.Territory
@Territory you only addressed one third of my comment.Hola
@Hola I was investigating. The problem has nothing to do with the previous activity. The question is what internal process is blocking the animation? I have made a single activity app that demonstrates the problem.Territory
I have the feeling that the onGlobalLayout() callback is being invoked earlier than you need it. Try starting your animation from a Runnable that you post to one your your Views in onCreate() instead.Argyrol
@DavidWasser thanks for the suggestion. I tried this and ran it a few times. onGlobalLayout() actually gets called about 10ms after the runnable runs that I post to the view, so the result is the same.Territory
@Territory thanks for the vids btw. It makes the issue abundantly clear (:Hola
@Hola Nothing unusual in the logs. My guess is that SOMETHING is happening in the activity for about 300ms after the views are laid out, but I have no idea what. I just want to be able to listen for when that thing is done so I can animate with skipping frames and without guessing how long that something takes.Territory
Hey, I'm having the exact same problem. Have you managed to fix it?Esau
I'm having this exact same problem as well. Any chance you've found a solution since?Sibylsibylla
@Sibylsibylla unfortunately, I did not. For other reasons, the UI was changed and this was no longer an issue.Territory
@Territory No problem. I finally found a solution here: #37958918Sibylsibylla
A
2

This happens because of the activity's transition animation, which is played while the activity is being created. As a result, your custom animation starts while the system is busy drawing the transition.

I haven't found a clean solution yet. For now, I'm simply waiting for the duration of the transition before starting my animation, but it is far from being perfect:

// The duration of the animation was found here:
// http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.5_r1/frameworks/base/core/res/res/anim/activity_open_enter.xml 
new Handler().postDelayed(runnable, android.R.integer.config_shortAnimTime);

You could also disable activity transitions instead, with:

overridePendingTransition(0, 0);

I'm still looking for a way to listen to the exact end time of the transition. Will keep you posted if I ever find a solution.

Afflict answered 5/10, 2016 at 9:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.