使用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
相关产品推荐
相关产品推荐

