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

Firebase Realtime Database结合LiveData/ViewModel实时更新失效问题排查

Firebase Realtime Database结合ViewModel/LiveData监听问题排查

问题概述

开发了一个DialogFragment,结合Firebase Realtime Database、ViewModel与LiveData实现数据库变化的持续监听,目前遇到两个问题:

  • onChanged方法仅触发一次,修改数据库数据后不再调用;
  • dataSnapshot始终为null,但ViewModel中的查询语句理论上应返回数据;
    同时疑问:Firebase Realtime Database是否支持实时数据更新?

DialogFragment实现代码

public class DialogFR_LevelEnd extends DialogFragment implements View.OnClickListener {
    public DialoagFragmentLevelEndingBinding binding;

    private double co2SavingsScore;

    private RecyclerView recyclerView_HighScore;

    private RV_Adapter_Highscore adapter_HighScore;
    private RecyclerView.LayoutManager layoutManager_HighScore;
    private ArrayList<RV_Item_Highscore> arrayList_HighScore;

    private int pastDaysForDisplayingScores = 0;
    private int currentLevel;

    //Firebase components
    private ViewModel_DialogFR_LevelEnd viewModel;
    LiveData<DataSnapshot> liveData;
    DataSnapshot currentDataSnapShotFromFirebase;
    DatabaseReference rootRef_Firebase;

    String FIREBASE_CO_2_SCORE = "co2_score";
    String FIREBASE_DATE = "date";
    String FIREBASE_DATE_IN_MILLISECONDS = "date_in_milliseconds";
    String FIREBASE_LEVEL = "level";
    String FIREBASE_NAME = "name";
    
    public static DialogFR_LevelEnd newInstance(double co2SavingsScore, double neededCO2SavingScore, int currentLevel) {
        DialogFR_LevelEnd fragment = new DialogFR_LevelEnd();
        Bundle args = new Bundle();
        args.putDouble("co2SavingsScore", co2SavingsScore);
        args.putDouble("neededCO2SavingScore", neededCO2SavingScore);
        args.putInt("currentLevel", currentLevel);
        fragment.setArguments(args);
        return fragment;
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        binding = DialoagFragmentLevelEndingBinding.inflate(inflater, container, false);
        double co2SavingsScore = getArguments().getDouble("co2SavingsScore", 0.0);
        double neededCO2SavingsScore = getArguments().getDouble("neededCO2SavingScore", 0.0);
        this.currentLevel = getArguments().getInt("currentLevel", 0);

        binding.textViewLevelFinishedMessageCO2.setText("You needed to save " + neededCO2SavingsScore+ "g of CO2 and you got " + co2SavingsScore + "g");

        //Check if the level was successfull
        if (co2SavingsScore>= neededCO2SavingsScore) {
            //Level passed
            binding.imageViewCloseSymbol.setVisibility(View.INVISIBLE);
        }
        else {
            //Level not passed
            binding.imageViewCheckmark.setVisibility(View.INVISIBLE);
            binding.imageViewRepeatSymbol.setClickable(false);
            binding.imageViewRepeatSymbol.setAlpha(0.5f);
            binding.textViewNextLevel.setAlpha(0.5f);
        }

        //Initialize highScore array list and the RV adapter
        arrayList_HighScore = new ArrayList<RV_Item_Highscore>();
        adapter_HighScore = new RV_Adapter_Highscore(arrayList_HighScore);


        //Firebase components
        String FIREBASE_URL = "https://heatinggamehighscores-default-rtdb.europe-west1.firebasedatabase.app/";

        if (FirebaseApp.getApps(getContext()).isEmpty()) {
            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setApplicationId("1:248974012708:android:3f93234ba2066ed41643b1")
                    .setDatabaseUrl(FIREBASE_URL)

                    .build();

            FirebaseApp.initializeApp(getContext(), options);
        }
        rootRef_Firebase = FirebaseDatabase.getInstance(FIREBASE_URL).getReference();
        rootRef_Firebase.keepSynced(true);


        // Initialize ViewModel
        viewModel = new ViewModelProvider(this).get(ViewModel_DialogFR_LevelEnd.class);
        viewModel.setFirebaseNodeLevel(currentLevel);
        viewModel.setPastTimeMillis(pastDaysForDisplayingScores);

        liveData = viewModel.getData();
        Log.e("Tag_Dialog", "DialogFragment: ViewModel Get Data Called");
        liveData.observe(this, new Observer<DataSnapshot>() {

            @Override
            public void onChanged(@Nullable DataSnapshot dataSnapshot) {
                Log.e("Tag_Dialog", "DialogFragment: onChanged Called");
                if (dataSnapshot != null) {

                    Log.e("Tag_Dialog", "DialogFragment: DataSnapshot !=null");

                    arrayList_HighScore.clear();


                    for(DataSnapshot ds: dataSnapshot.getChildren()) {
                        Log.e("Tag_Dialog", "DialogFragment: DataSnapshot iteration");
                        if (ds != null) {

                             String name = "";
                             int co2Score = 0;
                             String date = "";
                             int level = 0;

                             int position = 0;

                            // update the UI here with values in the snapshot
                            if(ds.child(FIREBASE_NAME).getValue(String.class)!=null) {
                                name = ds.child(FIREBASE_NAME).getValue(String.class);
                            }

                            if(ds.child(FIREBASE_CO_2_SCORE).getValue(Integer.class)!=null) {
                                co2Score = ds.child(FIREBASE_CO_2_SCORE).getValue(Integer.class);
                            }

                            if(ds.child(FIREBASE_LEVEL).getValue(Integer.class)!=null) {
                                level = ds.child(FIREBASE_LEVEL).getValue(Integer.class);
                            }


                            if(ds.child(FIREBASE_DATE).getValue(String.class)!=null) {
                                date =  ds.child(FIREBASE_DATE).getValue(String.class);
                            }
                            arrayList_HighScore.add(new RV_Item_Highscore(name, co2Score, date, level, position));

                        }
                    }
                }
            }// end onChange
        }); //end observe    

        buildRecyclerView();

        return binding.getRoot();    
    }

    public void buildRecyclerView() {
        recyclerView_HighScore = binding.rvHighScoreStatisticsToBeDisplayed;
        recyclerView_HighScore.setHasFixedSize(true);
        layoutManager_HighScore = new LinearLayoutManager(this.getContext());    

        recyclerView_HighScore.setLayoutManager(layoutManager_HighScore);
        recyclerView_HighScore.setAdapter(adapter_HighScore);
    }
    
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);    
    }    

    @Override
    public void onClick(View view) {
        if (view instanceof ToggleButton) {
            if (binding.tbuttonHighScoreLastWeek.isChecked()) {
                this.pastDaysForDisplayingScores = 7;
            }
            if (binding.tbuttonHighScoreLastMonth.isChecked()) {
                this.pastDaysForDisplayingScores = 30;
            }
            if (binding.tbuttonHighScoreOverall.isChecked()) {
                this.pastDaysForDisplayingScores = 10000;
            }
            viewModel.setPastTimeMillis(pastDaysForDisplayingScores);
        }
    }
}

ViewModel代码

public class ViewModel_DialogFR_LevelEnd extends ViewModel {        
    public static final String FIREBASE_URL = "https://heatinggamehighscores-default-rtdb.europe-west1.firebasedatabase.app/";
    public static String FIREBASE_NODE_LEVEL = "";
    public static final String FIREBASE_DATE_IN_MILLISECONDS = "date_in_milliseconds";

    private MutableLiveData<DataSnapshot> data = new MutableLiveData<DataSnapshot>();

    private static long pastTimeMillis;

    public void setFirebaseNodeLevel(int levelNumber) {
        FIREBASE_NODE_LEVEL = "level_" + levelNumber;
    }

    public void setPastTimeMillis (int pastDaysForDisplayingScores) {
        pastTimeMillis = System.currentTimeMillis() - (long) (pastDaysForDisplayingScores * 24L * 60 * 60 * 1000);
        data.postValue(null);
    }

    public LiveData<DataSnapshot> getData() {
        Log.e("Tag_Dialog", "ViewModel: getData called");
          Query QUERY_DATE = FirebaseDatabase.getInstance(FIREBASE_URL).getReference().child(FIREBASE_NODE_LEVEL).orderByChild(FIREBASE_DATE_IN_MILLISECONDS).startAt(pastTimeMillis);
        Log.e("Tag_Dialog", "ViewModel: Query =" + QUERY_DATE);
        return data;
    }
}

Firebase数据库结构

数据库根节点下包含多个以level_数字命名的节点(如level_1、level_2),每个level节点下有若干子节点,每个子节点包含以下字段:

  • co2_score:数值类型
  • date:字符串类型(日期)
  • date_in_milliseconds:数值类型(时间戳)
  • level:数值类型
  • name:字符串类型(用户名)

内容的提问来源于stack exchange,提问作者VanessaF

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 11:17:02