You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:10:27