快速点击计分按钮致乒乓球计分APP崩溃求助
从你的崩溃日志和代码来看,问题出在快速点击计分按钮时,多次并发触发过渡动画,导致TransitionManager内部的集合在迭代过程中被修改,从而抛出ConcurrentModificationException。下面一步步分析并解决:
崩溃原因分析
当你快速点击point1或point2按钮时,会频繁调用TransitionManager.beginDelayedTransition(trans, set),而前一个动画的TransitionListener还在执行onTransitionEnd方法(里面又发起了另一个fadeout过渡),这就导致TransitionManager内部维护的过渡集合在遍历过程中被修改,触发了并发修改异常。
另外还发现一个小bug:你的scoreIncrement方法里先执行了points++,但在点击事件里已经做了points1++/points2++,这会导致分数多算1分,比如第一次点击应该显示01,但实际会显示02,这个也需要修正。
具体解决方案
1. 添加动画运行状态标记,防止并发触发
在Activity里添加一个boolean变量,用来标记当前是否有过渡动画在运行,只有当动画结束后才能发起新的动画:
// 在类成员变量里添加 private boolean isTransitionRunning = false;
然后修改TransitionSet的Listener,更新这个标记:
set.addListener(new Transition.TransitionListener() { @Override public void onTransitionStart(Transition transition) { isTransitionRunning = true; } @Override public void onTransitionEnd(Transition transition) { fadeout.setStartDelay(500); // 给fadeout也添加监听,确保动画结束后重置状态标记 fadeout.addListener(new Transition.TransitionListener() { @Override public void onTransitionStart(Transition transition) {} @Override public void onTransitionEnd(Transition transition) { isTransitionRunning = false; serve.setVisibility(View.GONE); } @Override public void onTransitionCancel(Transition transition) { isTransitionRunning = false; } @Override public void onTransitionPause(Transition transition) {} @Override public void onTransitionResume(Transition transition) {} }); TransitionManager.beginDelayedTransition(trans,fadeout); } @Override public void onTransitionCancel(Transition transition) { isTransitionRunning = false; } @Override public void onTransitionPause(Transition transition) {} @Override public void onTransitionResume(Transition transition) {} });
在点击事件里触发动画前,先检查这个标记:
// point1的点击事件里 if(isServiceChange() && !isTransitionRunning){ TransitionManager.beginDelayedTransition(trans,set); serve.setVisibility(View.VISIBLE); } // point2的点击事件里同样修改 if (isServiceChange() && !isTransitionRunning) { TransitionManager.beginDelayedTransition(trans, set); serve.setVisibility(View.VISIBLE); }
2. 修正分数计算的bug
修改scoreIncrement方法,去掉多余的points++,因为点击事件里已经对points1/points2进行了自增:
String scoreIncrement(int points){ // 去掉这里的points++ if (points >= 10) return Integer.toString(points); return "0"+Integer.toString(points); }
同时调整点击事件里的调用顺序,先自增再设置文本:
// point1的点击事件 points1++; score1.setText(scoreIncrement(points1)); // point2的点击事件同理 points2++; score2.setText(scoreIncrement(points2));
3. 额外优化:避免重复设置相同的过渡
可以在发起过渡前,先检查serve的可见性,避免不必要的动画触发:
if(isServiceChange() && !isTransitionRunning && serve.getVisibility() != View.VISIBLE){ TransitionManager.beginDelayedTransition(trans,set); serve.setVisibility(View.VISIBLE); }
测试验证
修改完成后,快速点击计分按钮,应该不会再出现ConcurrentModificationException,同时分数计算也会正常显示。
内容的提问来源于stack exchange,提问作者Paritosh

