Android Java实现trivia游戏每10秒间隔执行10轮函数加载的最优方案
核心问题定位
- 你当前代码中
onCreate里的10次循环是主线程同步立即执行的,会在页面创建的瞬间跑完所有playGame()调用,完全没有等待题目展示间隔的环节。 - 之前使用
CountDownTimer失效的原因是,你在这个一次性跑完的循环里循环创建了10个独立的倒计时实例,所有定时器会同时启动,10秒后所有回调同时触发,自然达不到逐题间隔切换的效果。 - 现有代码存在空指针隐患:在
for循环里第一次调用playGame()时,还没有通过findViewById初始化答案按钮、题目文本框的实例,此时方法里操作的控件全是null。
实现方案
核心思路是串行驱动题目流程,不需要一次性加载所有题目:每加载完一题,启动一个10秒的单次延时任务,延时结束后判断是否还有剩余题目,有则加载下一题,没有则跳转游戏结算页。同时要兼容玩家主动点击答案立刻切下一题的场景。
修正后的核心代码
public class GameActivity extends AppCompatActivity { // 单题展示时长10秒 private static final long QUESTION_DURATION_MS = 10_000; // 当前题目的序号 private int questionCount = 0; // 全局持有当前题目的倒计时实例,方便后续取消 private CountDownTimer questionTimer; // 界面控件 private Button answerOneBtn, answerTwoBtn, answerThreeBtn, answerFourBtn; private TextView questionTextView; // 游戏状态 private int playerScore = 0; private Game currentGame = new Game(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_game); currentGame.questionList.AnswersJumbled(); // 提前完成所有控件初始化,避免空指针 answerOneBtn = findViewById(R.id.AnswerOneButton); answerTwoBtn = findViewById(R.id.AnswerTwoButton); answerThreeBtn = findViewById(R.id.AnswerThreeButton); answerFourBtn = findViewById(R.id.AnswerFourButton); questionTextView = findViewById(R.id.questionText); // 绑定统一的答案点击事件:点击后取消当前倒计时,立刻切下一题 View.OnClickListener answerClickHandler = v -> { if (questionTimer != null) questionTimer.cancel(); currentGame.playerOneSelection = ((Button) v).getText().toString(); // 这里补充答题判分、更新分数的逻辑 loadNextQuestion(); }; answerOneBtn.setOnClickListener(answerClickHandler); answerTwoBtn.setOnClickListener(answerClickHandler); answerThreeBtn.setOnClickListener(answerClickHandler); answerFourBtn.setOnClickListener(answerClickHandler); // 游戏启动,加载第一道题 playGame(); } // 加载单道题目 public void playGame() { currentGame.loadQuestion(questionCount); questionTextView.setText(currentGame.currentQuestion); answerOneBtn.setText(currentGame.firstAnswer); answerTwoBtn.setText(currentGame.secondAnswer); answerThreeBtn.setText(currentGame.thirdAnswer); answerFourBtn.setText(currentGame.fourthAnswer); // 题目加载完成后启动10秒倒计时,超时无操作自动切下一题 questionTimer = new CountDownTimer(QUESTION_DURATION_MS, QUESTION_DURATION_MS) { @Override public void onTick(long millisUntilFinished) { // 不需要逐秒倒计时显示的话,此方法无需额外逻辑 } @Override public void onFinish() { // 超时未操作,自动加载下一题 loadNextQuestion(); } }.start(); } // 统一的切下一题入口,消除重复逻辑 private void loadNextQuestion() { questionCount++; // 10题全部加载完成,跳转结算页 if (questionCount >= 10) { // 这里补充跳转到结算页面的逻辑 finish(); return; } // 加载下一道题 playGame(); } @Override protected void onDestroy() { super.onDestroy(); // 页面销毁时取消倒计时,避免内存泄漏 if (questionTimer != null) { questionTimer.cancel(); questionTimer = null; } } }
注意事项
- 不要把倒计时的创建逻辑放在同步循环里,否则会生成多个同时运行的定时器,造成回调并发触发。
- 答题切题、超时切题走统一的入口方法,避免逻辑分散出现bug。
- 页面销毁时必须取消正在运行的倒计时,否则会因倒计时回调持有Activity引用引发内存泄漏。
内容的提问来源于stack exchange,提问作者kiotzu
相关产品推荐
相关产品推荐

