侧边栏壁纸
  • 累计撰写 402 篇文章
  • 累计创建 63 个标签
  • 累计收到 122 条评论

目 录CONTENT

文章目录

异常:Animators may only be resumed from the same thread that the animator was started on

Z同学
2022-12-31 / 0 评论 / 1 点赞 / 27 阅读 / 612 字
温馨提示:
本文最后更新于 2023-01-09,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1. 介绍

在使用Animator进行动画控制时,最近触发了上面的崩溃异常日志:

Animators may only be resumed from the same thread that the animator was started on

意思就是动画的恢复,只能在动画创建时的线程中进行恢复。

调用的是ValueAnimator动画中的resume方法时,出现的问题。

主要原因就在于,我们创建ValueAnimator类的时候,是在主线程中进行初始化的,后面再resume()方法进行恢复运动状态时,是通过子线程中触发的。就会出现上面的错误了。

因为ValueAnimator在动画开始的时候都会检测:Looper.myLoope()

这时候就会触发异常了。

2.解释

Looper.myLooper()的作用是:获取当前线程的Looper对象。而我们在子线程中通常是没有Looper的,特别是通过

Executors.newSingleThreadExecutor()创建的单线程是没有Looper对象的。

所以我们如果在普通的子线程中触发Animator的播放start,取消cancel,结束end,恢复resume方法都会触发异常。

大部分情况下异常内容为:Animators may only be run on Looper threads

而resume的异常为:Animators may only be resumed from the same thread that the animator was started on

ValueAnimator源码:

 @Override
    public void end() {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        if (!mRunning) {
            // Special case if the animation has not yet started; get it ready for ending
            startAnimation();
            mStarted = true;
        } else if (!mInitialized) {
            initAnimation();
        }
        animateValue(shouldPlayBackward(mRepeatCount, mReversing) ? 0f : 1f);
        endAnimation();
    }

@Override
    public void resume() {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be resumed from the same " +
                    "thread that the animator was started on");
        }
        if (mPaused && !mResumed) {
            mResumed = true;
            if (mPauseTime > 0) {
                addAnimationCallback(0);
            }
        }
        super.resume();
    }

所以,通常都是在主线程中创建和对Animator进行管理。

我们如果需要通过子线程切换到主线程进行处理,方法有很多。

方法1:

ContextCompat.getMainExecutor(context).execute(() -> {
                animator.resume();
});

方法2:(该Handler是在Activity中创建的)

myHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        animator.resume();
                    }
                });

方法3:(在Activity中调用)

 runOnUiThread(new Runnable() {
            @Override
            public void run() {
                 animator.resume();
            }
        });

方法4:使用MediatorLiveData进行监听和回调

在子线程中,通过livedatepostValue更新状态。在主线程的LiveData中通过observe进行得到结果。

还有很多其他的方法。可以实现子线程和主线程中的切换和状态传递。

1

评论区