美文网首页
属性动画AnimatorListener中onAnimation

属性动画AnimatorListener中onAnimation

作者: 碧桃鹦鹉 | 来源:发表于2019-01-04 20:13 被阅读0次

    在项目中有一个这样的场景,A动画播放完之后立即播放B动画。间隔一定时间之后,B动画reverse反转播放,播放完之后再reverse播放A动画。效果看上去是一个整体的顺序执行的动画。 我的做法是,为A动画B动画分别设定一个ValueAnimator,然后再各自的动画监听AnimatorListener中控制谁先谁后。但是在A动画的AnimatorListener的onAnimationEnd回调中去判断A动画isRunning()时,居然是输出的true,而且是在有些设备上会出现这样的结果。

    valueAnimator = ValueAnimator.ofFloat(0f, 1f);
    valueAnimator.setDuration(1000);
    valueAnimator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
        }
        @Override
        public void onAnimationEnd(Animator animation) {
            System.out.println("valueAnimator.isRunning() " + valueAnimator.isRunning());
        }
        @Override
        public void onAnimationCancel(Animator animation) {
        }
        @Override
        public void onAnimationRepeat(Animator animation) {
        }
    });
    valueAnimator.start();
    

    运行在两台测试手机,一台是华为PRA-AL00输出false,一台是OPPO A37m输出true。这样的问题说大不大,说小不小。在End的时候,询问是否在运行,居然是确定的答案,很不可思议,就打算研究一下这个事。
    查看ValueAnimator的isRunning()源码:

    @Override
    public boolean isRunning() {
        return mRunning;
    }
    

    发现只是返回mRunning这个字段,推测应该是mRunning这个字段没在合适的时候修改为false,那就查看一下mRunning这个字段什么时候被设置为false。由于在断点调试的过程中,调试的代码行号和实际的对不上,所以根本找不到代码执行到哪里,看其他网友分享解决行号对不上的时候,有的人说如果按着解决方法做了还是对不上的话,那就是手机厂商深度定制了系统,修改了源码。。。所以通过查看源码的方式就不行了。
    那也要找到是什么情况下导致这个返回结果不对,所以我尝试在onAnimationEnd中停一秒再获取:

     @Override
     public void onAnimationEnd(Animator animation) {
         System.out.println("valueAnimator.isRunning() " + valueAnimator.isRunning());
         new Thread(new Runnable() {
             @Override
             public void run() {
                 try {
                     Thread.sleep(1000);
                     System.out.println("thread valueAnimator.isRunning() " + valueAnimator.isRunning());
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }).start();
     }
    

    输出结果为:

    01-04 21:25:11.805 21056-21056/com.liuan.face.face I/System.out: valueAnimator.isRunning() true
    01-04 21:25:12.806 21056-21307/com.liuan.face.face I/System.out: thread valueAnimator.isRunning() false
    

    看来还是改变成false了 可能是获取的时机不对,那到底是什么时候呢?在刚才的线程中增加:

    while (i < 1000) {
        System.out.println("thread while valueAnimator.isRunning() " + valueAnimator.isRunning());
        i++;
    }
    

    输出结果为 1000行的false。看来不是时机不对,可能是开了线程的原因。看看到底是什么时候true变成了false:

    @Override
    public void onAnimationEnd(Animator animation) {
        System.out.println("valueAnimator.isRunning() " + valueAnimator.isRunning());
        for (int i = 0; i < 1000; i++) {
            System.out.println("for valueAnimator.isRunning() " + valueAnimator.isRunning());
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("while valueAnimator.isRunning() " + valueAnimator.isRunning());
            }
        }).start();
    }
    

    输出结果为1000个true之后是一个false。
    继续修改代码为让主线程的和子线程的同时交错输出:

    @Override
    public void onAnimationEnd(Animator animation) {
        System.out.println("valueAnimator.isRunning() " + valueAnimator.isRunning());
        new Thread(new Runnable() {
            int i = 0;
            @Override
            public void run() {
                while (i < 1000) {
                    System.out.println("while valueAnimator.isRunning() " + valueAnimator.isRunning());
                    i++;
                }
            }
        }).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("for valueAnimator.isRunning() " + valueAnimator.isRunning());
        }
    }
    

    这时候就有意思了,输出结果为两种不规则交替输出,并且结果都是true。在这之前以为开线程才是唯一保险的方法,现在看来,虽然子线程中获取到了false,但是之后在主线程里再去获取的时候,mRunning又被赋值为true。
    根据上面的实验推测,可能是手机厂商对源码的深度改造,也可能是手机内核对线程的分配方式不同,也可能是两个原因同时存在,导致这样“奇妙”的现象。
    但是功能毕竟要实现,源码不靠谱,那就靠自己,增加一个boolean值用来判断:

    valueAnimator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
            isRunning = true;
        }
        @Override
        public void onAnimationEnd(Animator animation) {
            isRunning = false;
        }
        @Override
        public void onAnimationCancel(Animator animation) {
        }
        @Override
        public void onAnimationRepeat(Animator animation) {
        }
    });
    

    这时候在onAnimationEnd之后不是调valueAnimator.isRunning(),而是获取isRunning的值,这样就确保不会有问题了。

    伸懒腰

    相关文章

      网友评论

          本文标题:属性动画AnimatorListener中onAnimation

          本文链接:https://www.haomeiwen.com/subject/sdokrqtx.html