使用 ViewCompat 时出现 StackOverflowError

StackOverflowError when using ViewCompat

我正在使用 viewCompat 来兼容我的动画以降低 api (10)。

但是当我在模拟器上部署它时,我得到 WhosebugError

这是我的代码:

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();


    }

}

这是错误:

 java.lang.WhosebugError
                                                                       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.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.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.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.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.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.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.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.onAnimationEnd(MainActivity.java:305)
                                                                    at android.support.v4.view.ViewPropertyAnimatorCompat$BaseViewPropertyAnimat

如您所见,错误返回到代码的 onAnimationEnd 部分。

你在 ViewCompat.animate(floatingActionButton) 内部调用 ViewCompat.animate(floatingActionButton) 所以你得到一个无限循环:

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

                @Override
                public void onAnimationCancel(View view) {

                }
            })
            .start();

如果我们查看源代码,我们会看到兼容 animate 方法的实现之一是:

@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;
}

所以在内部兼容动画中使用附加到您的视图的动画器缓存。现在让我们 return 处理您的情况。您有观点 floatingActionButton。你为此打电话 ViewCompat.animate() 。然后在内部实现中创建 ViewPropertyAnimatorCompat 并将其分配给您的视图。然后你 set'ing listener for it.

动画完成后,您再次调用 animate,而不是创建新的 ViewPropertyAnimatorCompat(这似乎合乎逻辑),您收到了先前使用分配的侦听器创建的 ViewPropertyAnimatorCompat。因此你有无限循环。

要修复它,您需要编写如下内容:

    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();

总之需要在onAnimationEnd回调

中添加.setListener(null)构建动画