MAY3AM
MAY3AM

Reputation: 1212

StackOverflowError when using ViewCompat

I'm using viewCompat to compatible my animation to lower api (10).

But when I deploy this on emulator I get StackOverflowError

This is my code:

private void fabFadeIn(){

    if (floatingActionButton.getVisibility() == View.GONE) {

        floatingActionButton.setVisibility(View.VISIBLE);

        ViewCompat.setAlpha(floatingActionButton, 0f);
        ViewCompat.setScaleX(floatingActionButton, 0f);
        ViewCompat.setScaleY(floatingActionButton, 0f);

        ViewCompat.animate(floatingActionButton)
                .alpha(1)
                .scaleX(1)
                .scaleY(1)
                .setDuration(300)
                .setInterpolator(new OvershootInterpolator())
                .setListener(new ViewPropertyAnimatorListener() {
                    @Override
                    public void onAnimationStart(View view) {

                    }

                    @Override
                    public void onAnimationEnd(View view) {
                        ViewCompat.animate(floatingActionButton).setInterpolator(new LinearOutSlowInInterpolator()).start();
                    }

                    @Override
                    public void onAnimationCancel(View view) {

                    }
                })
                .start();


    }

}

And this is error:

 java.lang.StackOverflowError
                                                                       at java.lang.Thread.currentThread(Thread.java:557)
                                                                       at java.lang.ThreadLocal.get(ThreadLocal.java:59)
                                                                       at android.view.ViewRoot.getRunQueue(ViewRoot.java:3340)
                                                                       at android.view.View.removeCallbacks(View.java:5407)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.removeStartMessage(ViewPropertyAnimatorCompat.java:341)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.start(ViewPropertyAnimatorCompat.java:268)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat.start(ViewPropertyAnimatorCompat.java:1249)
                                                                       at com.test.app.activities.MainActivity$2.onAnimationEnd(MainActivity.java:305)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.startAnimation(ViewPropertyAnimatorCompat.java:308)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.start(ViewPropertyAnimatorCompat.java:269)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat.start(ViewPropertyAnimatorCompat.java:1249)
                                                                       at com.test.app.activities.MainActivity$2.onAnimationEnd(MainActivity.java:305)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.startAnimation(ViewPropertyAnimatorCompat.java:308)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.start(ViewPropertyAnimatorCompat.java:269)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat.start(ViewPropertyAnimatorCompat.java:1249)
                                                                       at com.test.app.activities.MainActivity$2.onAnimationEnd(MainActivity.java:305)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.startAnimation(ViewPropertyAnimatorCompat.java:308)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.start(ViewPropertyAnimatorCompat.java:269)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat.start(ViewPropertyAnimatorCompat.java:1249)
                                                                       at com.test.app.activities.MainActivity$2.onAnimationEnd(MainActivity.java:305)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.startAnimation(ViewPropertyAnimatorCompat.java:308)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.start(ViewPropertyAnimatorCompat.java:269)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat.start(ViewPropertyAnimatorCompat.java:1249)
                                                                       at com.test.app.activities.MainActivity$2.onAnimationEnd(MainActivity.java:305)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.startAnimation(ViewPropertyAnimatorCompat.java:308)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.start(ViewPropertyAnimatorCompat.java:269)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat.start(ViewPropertyAnimatorCompat.java:1249)
                                                                       at com.test.app.activities.MainActivity$2.onAnimationEnd(MainActivity.java:305)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.startAnimation(ViewPropertyAnimatorCompat.java:308)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.start(ViewPropertyAnimatorCompat.java:269)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat.start(ViewPropertyAnimatorCompat.java:1249)
                                                                       at com.test.app.activities.MainActivity$2.onAnimationEnd(MainActivity.java:305)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.startAnimation(ViewPropertyAnimatorCompat.java:308)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimatorCompatImpl.start(ViewPropertyAnimatorCompat.java:269)
                                                                       at android.support.v4.view.ViewPropertyAnimatorCompat.start(ViewPropertyAnimatorCompat.java:1249)
                                                                       at com.test.app.activities.MainActivity$2.onAnimationEnd(MainActivity.java:305)
                                                                    at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimat

As you can see error goes back to onAnimationEnd section of code.

Upvotes: 0

Views: 486

Answers (2)

Mikhail Spitsin
Mikhail Spitsin

Reputation: 2608

If we go to the sources, we will see, that one of realisations of compatible animate method is:

@Override
public ViewPropertyAnimatorCompat animate(View view) {
    if (mViewPropertyAnimatorCompatMap == null) {
        mViewPropertyAnimatorCompatMap = new WeakHashMap<>();
    }
    ViewPropertyAnimatorCompat vpa = mViewPropertyAnimatorCompatMap.get(view);
    if (vpa == null) {
        vpa = new ViewPropertyAnimatorCompat(view);
        mViewPropertyAnimatorCompatMap.put(view, vpa);
    }
    return vpa;
}

So in internal compatible animations use cache of Animators attached to your view. Now let's return to your case. You have view floatingActionButton. And you call ViewCompat.animate() for it. Then in internal implementations ViewPropertyAnimatorCompat is created and assigned to your view. Then you set'ing listener for it.

After animation is finished you call animate again and instead of creating new ViewPropertyAnimatorCompat (it seems logicaly) you received previously created ViewPropertyAnimatorCompat with your assigned listener. And thus you have endless loop.

To fix it, you need to write something like:

    ViewCompat.animate(floatingActionButton)
            .alpha(1)
            .scaleX(1)
            .scaleY(1)
            .setDuration(300)
            .setInterpolator(new OvershootInterpolator())
            .setListener(new ViewPropertyAnimatorListener() {
                @Override
                public void onAnimationStart(View view) {

                }

                @Override
                public void onAnimationEnd(View view) {
                    ViewCompat.animate(floatingActionButton).setInterpolator(new LinearOutSlowInInterpolator()).setListener(null).start();
                }

                @Override
                public void onAnimationCancel(View view) {

                }
            })
            .start();

In short, you need to add .setListener(null) to building animation in onAnimationEnd callback

Upvotes: 3

Jens
Jens

Reputation: 69505

You call ViewCompat.animate(floatingActionButton) inside of ViewCompat.animate(floatingActionButton) so you get an endless loop:

   ViewCompat.animate(floatingActionButton)
....                    
                @Override
                public void onAnimationEnd(View view) {
                    ViewCompat.animate(floatingActionButton).setInterpolator(new LinearOutSlowInInterpolator()).start();
                }

                @Override
                public void onAnimationCancel(View view) {

                }
            })
            .start();

Upvotes: 2

Related Questions