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
进行监听和回调
在子线程中,通过livedate
的postValue
更新状态。在主线程的LiveData
中通过observe
进行得到结果。
还有很多其他的方法。可以实现子线程和主线程中的切换和状态传递。
评论区