Android中如何刷新Firebase数据库引用获取下一题?
问题梳理与解决方案
你的核心问题很明确:每次点击选项后只是单纯增加了题号,但没有更新数据库的引用路径去获取对应题号的题目,而且还有个隐藏坑——你把按钮点击监听放在onDataChange方法里,每次数据变化都会重复绑定监听,很容易触发多次执行的问题。
下面是调整后的完整代码,我会在后面解释关键修改点:
public class TakingQuiz extends AppCompatActivity { TextView que; TextView sco; TextView qn; Button opt1; Button opt2; Button opt3; Button opt4; String RecieversId; Integer mScore = 0; Integer mQuestionNumber = 1; String question; String option1; String option2; String option3; String option4; String answer; FirebaseAuth mAuth; FirebaseUser currentUser; DatabaseReference mDatabaseReference; // 声明监听变量,方便后续移除旧监听 ValueEventListener questionListener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.taking_quiz); // 简化findViewById写法(API 26+支持) que = findViewById(R.id.txtQuestion); opt1 = findViewById(R.id.button1); opt2 = findViewById(R.id.button2); opt3 = findViewById(R.id.button3); opt4 = findViewById(R.id.button4); qn = findViewById(R.id.number); sco = findViewById(R.id.score); qn.setText("1"); sco.setText("Score : 0"); RecieversId = getIntent().getStringExtra("Recievers_Id"); mAuth = FirebaseAuth.getInstance(); currentUser = mAuth.getCurrentUser(); mDatabaseReference = FirebaseDatabase.getInstance().getReference(); // 按钮监听只绑定一次,避免重复绑定 setupOptionClickListeners(); // 加载第一题 updateQuestion(); } private void setupOptionClickListeners() { opt1.setOnClickListener(v -> handleOptionSelection(option1, v)); opt2.setOnClickListener(v -> handleOptionSelection(option2, v)); opt3.setOnClickListener(v -> handleOptionSelection(option3, v)); opt4.setOnClickListener(v -> handleOptionSelection(option4, v)); } private void handleOptionSelection(String selectedOption, View clickedView) { // 判断选项是否正确并更新UI if (selectedOption.equals(answer)) { ((Button)clickedView).setBackgroundColor(Color.GREEN); mScore++; sco.setText("Score : " + mScore); } else { ((Button)clickedView).setBackgroundColor(Color.RED); } // 延迟1秒加载下一题,让用户能看到对错反馈 new Handler(Looper.getMainLooper()).postDelayed(() -> { mQuestionNumber++; qn.setText("Question : " + mQuestionNumber); // 重置按钮背景色 resetOptionButtonColors(); // 加载对应题号的新题目 updateQuestion(); }, 1000); } private void resetOptionButtonColors() { // 用系统默认背景色重置,也可以换成你布局里的原始颜色 int defaultColor = ContextCompat.getColor(this, android.R.color.background_light); opt1.setBackgroundColor(defaultColor); opt2.setBackgroundColor(defaultColor); opt3.setBackgroundColor(defaultColor); opt4.setBackgroundColor(defaultColor); } private void updateQuestion() { // 先移除旧的监听,避免内存泄漏和重复触发 if (questionListener != null) { mDatabaseReference.child("Users") .child(RecieversId) .child("Quiz") .child("Question" + mQuestionNumber) .removeEventListener(questionListener); } // 动态构造当前题号的数据库引用 DatabaseReference currentQuestionRef = mDatabaseReference.child("Users") .child(RecieversId) .child("Quiz") .child("Question" + mQuestionNumber); questionListener = currentQuestionRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // 判断当前题号的题目是否存在,处理测验结束逻辑 if (!dataSnapshot.exists()) { que.setText("Quiz Completed! Final Score: " + mScore); // 禁用所有选项按钮 opt1.setEnabled(false); opt2.setEnabled(false); opt3.setEnabled(false); opt4.setEnabled(false); return; } // 从数据库读取题目数据 question = dataSnapshot.child("Question").getValue(String.class); answer = dataSnapshot.child("Answer").getValue(String.class); option1 = dataSnapshot.child("Option1").getValue(String.class); option2 = dataSnapshot.child("Option2").getValue(String.class); option3 = dataSnapshot.child("Option3").getValue(String.class); option4 = dataSnapshot.child("Option4").getValue(String.class); // 更新UI显示题目 que.setText(question); opt1.setText(option1); opt2.setText(option2); opt3.setText(option3); opt4.setText(option4); } @Override public void onCancelled(DatabaseError databaseError) { Toast.makeText(TakingQuiz.this, "Failed to load question", Toast.LENGTH_SHORT).show(); } }); } }
核心修改点说明
- 动态构造数据库引用:每次调用
updateQuestion()时,都会根据当前的mQuestionNumber生成QuestionX的路径,这样就能自动拉取对应题号的题目。 - 分离按钮监听逻辑:把点击监听移到
setupOptionClickListeners()中,在onCreate只绑定一次,避免重复绑定导致的多次执行问题。 - 统一选项处理逻辑:用
handleOptionSelection()方法处理所有选项的点击,减少重复代码,同时添加延迟加载让用户能看到对错反馈。 - 移除旧监听:每次加载新题前移除之前的监听,避免内存泄漏和多个监听同时触发的问题。
- 添加测验结束判断:当数据库中没有对应题号的题目时,自动结束测验并显示最终得分。
内容的提问来源于stack exchange,提问作者user9020006
相关产品推荐
相关产品推荐

