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

使用MVVM架构从Firebase数据库获取LiveData失败,无报错提示

问题描述

我是编程新手,正在使用Java开发。按照线上教程采用MVVM架构从Firebase数据库获取LiveData,但Fragment中没有任何数据显示或获取到,整个项目无任何报错信息,不清楚问题出在哪里。

相关代码

Repository代码

package com.example.echat.Repository;

import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;


import com.example.echat.Utils.Util;
import com.example.echat.UserModel;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

 public class ProfileRepository {

    private DatabaseReference databaseReference;
    private Util util = new Util();
    private MutableLiveData<UserModel> liveData;
    private static ProfileRepository profileRepository;

    public static ProfileRepository getInstance(){
        return profileRepository = new ProfileRepository();
    }


    public LiveData<UserModel>getUser(){
        if (liveData==null) {
            liveData=new MutableLiveData<>();
            databaseReference = FirebaseDatabase.getInstance().getReference("Users");
            databaseReference.child(util.getUID()).addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {
                    if (snapshot.exists()) {
                        UserModel userModel = snapshot.getValue(UserModel.class);
                        liveData.setValue(userModel);
                    }
                }

                @Override
                public void onCancelled(@NonNull DatabaseError error) {

                }
            });
        }
        return liveData;
    }
}

Util代码

package com.example.echat.Utils;

import com.google.firebase.auth.FirebaseAuth;

public class Util {
    private FirebaseAuth firebaseAuth;

    public String getUID(){
        firebaseAuth=FirebaseAuth.getInstance();
        return firebaseAuth.getUid();
    }
}

ViewModel代码

package com.example.echat.ViewModel;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import com.example.echat.Repository.ProfileRepository;
import com.example.echat.UserModel;

public class ProfileViewModel extends ViewModel {

    private MutableLiveData<UserModel> userModelMutableLiveData = new MutableLiveData<>();
    ProfileRepository profileRepository = ProfileRepository.getInstance();

    public LiveData<UserModel> getUser(){
        return profileRepository.getUser();

    }
}

Profile Fragment代码

package com.example.echat.Fragments;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;

import com.example.echat.UserModel;
import com.example.echat.ViewModel.ProfileViewModel;
import com.example.echat.databinding.FragmentProfileBinding;

/**
 * A simple {@link Fragment} subclass.
 * Use the {@link ProfileFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class ProfileFragment extends Fragment {
    private FragmentProfileBinding binding;
    private ProfileViewModel profileViewModel;


    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    // TODO: Rename and change types of parameters
    private String mParam1;
    private String mParam2;

    public ProfileFragment() {
        // Required empty public constructor
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment ProfileFragment.
     */
    // TODO: Rename and change types and number of parameters
    public static ProfileFragment newInstance(String param1, String param2) {
        ProfileFragment fragment = new ProfileFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        binding=FragmentProfileBinding.inflate(inflater,container,false);
        View view = binding.getRoot();

        profileViewModel= ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication()).create(ProfileViewModel.class);

        Observer<UserModel> observer = userModel -> {
            binding.setUserModel(userModel);

            String name = userModel.getName();
            if (name.contains(" ")) {
                String[] split = name.split(" ");
                binding.txtProfileFName.setText(split[0]);
                binding.txtProfileLName.setText(split[1]);
            } else {
                binding.txtProfileFName.setText(name);
                binding.txtProfileLName.setText("");
            }

        };
        profileViewModel.getUser().observe(getViewLifecycleOwner(),observer);
        return view;
    }
}

UserModel代码

package com.example.echat;

import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.databinding.BindingAdapter;

import com.bumptech.glide.Glide;

import de.hdodenhof.circleimageview.CircleImageView;

public class UserModel {

    String name, status, image, number, uID, online, typing, token;

    public UserModel() {
    }

    public UserModel(String name, String status, String image, String number, String uID, String online, String typing, String token) {
        this.name = name;
        this.status = status;
        this.image = image;
        this.number = number;
        this.uID = uID;
        this.online = online;
        this.typing = typing;
        this.token = token;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public String getTyping() {
        return typing;
    }

    public void setTyping(String typing) {
        this.typing = typing;
    }

    public String getOnline() {
        return online;
    }

    public void setOnline(String online) {
        this.online = online;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getuID() {
        return uID;
    }

    public void setuID(String uID) {
        this.uID = uID;
    }

    @BindingAdapter("imageUrl")
    public static void loadImage(@NonNull CircleImageView view, @NonNull String image) {
        Glide.with(view.getContext()).load(image).into(view);
    }


}

排查与解决方案

1. 验证用户登录状态与UID正确性

在ProfileRepository的getUser()方法中添加日志,确认当前用户UID是否有效:

public LiveData<UserModel> getUser(){
    if (liveData==null) {
        liveData=new MutableLiveData<>();
        String uid = util.getUID();
        Log.d("ProfileRepo", "当前用户UID: " + uid);
        if(uid == null){
            Log.e("ProfileRepo", "用户未登录,UID为空");
            return liveData;
        }
        databaseReference = FirebaseDatabase.getInstance().getReference("Users");
        databaseReference.child(uid).addListenerForSingleValueEvent(new ValueEventListener() {
            // ... 原有代码
        });
    }
    return liveData;
}

如果UID为空,说明用户未完成登录流程,需要先实现登录逻辑后再获取数据。

2. 检查Firebase数据库数据结构

  • 登录Firebase控制台,确认Users节点下存在对应UID的数据条目。
  • 确保数据库中的字段名与UserModel类中的字段名完全一致(区分大小写),比如uID不能写成uid或UID,否则Gson无法自动映射。

3. 修复Repository单例实现

当前getInstance()每次调用都会创建新实例,导致liveData重复初始化,改为双重校验锁的单例模式:

private static ProfileRepository profileRepository;
public static ProfileRepository getInstance(){
    if(profileRepository == null){
        synchronized (ProfileRepository.class){
            if(profileRepository == null){
                profileRepository = new ProfileRepository();
            }
        }
    }
    return profileRepository;
}

4. 完善数据库错误回调

在onCancelled中添加错误日志,排查数据库请求失败原因:

@Override
public void onCancelled(@NonNull DatabaseError error) {
    Log.e("ProfileRepo", "数据库请求失败: " + error.getMessage() + " 错误码: " + error.getCode());
}

5. 处理Observer中的空指针问题

在Fragment的Observer中先判断userModel是否为空,避免空指针异常:

Observer<UserModel> observer = userModel -> {
    if(userModel == null){
        Log.d("ProfileFragment", "未获取到用户数据");
        return;
    }
    binding.setUserModel(userModel);
    String name = userModel.getName();
    if (name != null && name.contains(" ")) {
        String[] split = name.split(" ");
        binding.txtProfileFName.setText(split[0]);
        binding.txtProfileLName.setText(split[1]);
    } else {
        binding.txtProfileFName.setText(name != null ? name : "");
        binding.txtProfileLName.setText("");
    }
};

6. 优化ViewModel初始化

由于你的ViewModel不需要依赖Application,简化初始化方式:

profileViewModel = new ViewModelProvider(this).get(ProfileViewModel.class);

7. 确认Data Binding配置正确性

检查fragment_profile.xml中的数据绑定变量是否正确定义:

<layout>
    <data>
        <variable
            name="userModel"
            type="com.example.echat.UserModel" />
    </data>
    <!-- 布局内容 -->
</layout>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:22:07