Android Studio中同方法内按钮两次颜色切换为何仅显示最终效果
问题核心原因
所有点击事件的处理逻辑默认运行在Android**主线程(UI线程)**上,View的重绘不是执行完setBackgroundColor就立刻触发的:系统需要等当前主线程队列里的所有同步任务执行完毕,才会调用View的onDraw方法把最新的属性值渲染到屏幕上。
你当前的代码执行顺序是:
- 给按钮b1设置白色背景
- 调用delay方法让主线程阻塞300ms
- 给按钮b1设置绿色背景
这三步全程在主线程的同一个任务块里顺序执行,等300ms阻塞结束、任务跑完,系统终于有机会重绘界面时,按钮的背景属性已经是最终的绿色了,白色的状态从来没有被渲染到屏幕的机会,自然看不到中间变色过程。
另外你实现的delay方法直接调用Thread.sleep阻塞主线程是非常危险的写法,一旦延迟时间超过系统阈值,应用会直接弹出无响应(ANR)的崩溃弹窗。
正确实现方式
- 用View自带的
postDelayed能力把延迟执行的任务从当前流程中拆出来,全程不阻塞主线程:
首先定义一个成员变量保存切绿色的任务,方便后续清理排队的过期任务:
替换onClick中的代码如下:private final Runnable changeToGreenTask = () -> b1.setBackgroundColor(Color.GREEN);
这种方式下,onClick方法执行完设置白色的逻辑后会立刻返回,主线程会马上把白色状态渲染到屏幕上,等300ms时间到了,再执行切绿色的操作,全程不会阻塞UI响应。public void onClick(View v) { if (v == b1) { // 先清空之前还在排队的延迟任务,避免快速点击时状态错乱 b1.removeCallbacks(changeToGreenTask); b1.setBackgroundColor(Color.WHITE); // 将切绿色的任务延后300ms加入主线程执行队列 b1.postDelayed(changeToGreenTask, 300); } } - 如果需要更顺滑的视觉效果,可以用属性动画实现带过渡的变色效果,无需手动管理延迟逻辑:
public void onClick(View v) { if (v == b1) { b1.setBackgroundColor(Color.WHITE); ObjectAnimator.ofArgb(b1, "backgroundColor", Color.WHITE, Color.GREEN) .setStartDelay(300) // 延迟300ms再开始变色 .setDuration(200) // 变色动画持续200ms,要瞬切就设为0 .start(); } }
内容的提问来源于stack exchange,提问作者Yackov Grimberg
相关产品推荐
相关产品推荐

