Java类间ArrayList共享:如何在两个Fragment间传递Firebase读取的列表数据
问题原因
你遇到的空指针报错是因为第二个Fragment里声明的Dashboard db变量没有赋值,直接调用方法自然会抛出空引用异常。除此之外你还会遇到第二个问题:Firebase的addValueEventListener是异步回调,就算你拿到了Dashboard实例,也可能出现调用TrasactionExpenses()时数据还没从Firebase加载完成,返回空列表的情况。
推荐解决方案
方案1:使用共享ViewModel(官方推荐Fragment间共享数据的方式)
这是Android Jetpack推荐的同Activity下Fragment共享数据的方案,不需要互相持有实例,也不用处理生命周期问题:
- 先创建共享的ViewModel类
public class SharedViewModel extends ViewModel { // 用MutableLiveData包裹列表可以监听数据变化,解决Firebase异步问题 private final MutableLiveData<List<Catergory_List>> catList = new MutableLiveData<>(new ArrayList<>()); public void setCatList(List<Catergory_List> list) { catList.setValue(list); } public LiveData<List<Catergory_List>> getCatList() { return catList; } }
- 在Dashboard Fragment中加载完数据后更新ViewModel
// 先在Dashboard里初始化ViewModel,注意ViewModelProvider要传宿主Activity private SharedViewModel sharedViewModel; // 在onViewCreated生命周期中初始化 sharedViewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class); private void GetCategory() { DatabaseReference db = FirebaseDatabase.getInstance().getReference("Category"); db.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { List<Catergory_List> tempList = new ArrayList<>(); for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) { Catergory_List cl = userSnapshot.getValue(Catergory_List.class); tempList.add(cl); } // 更新ViewModel的数据 sharedViewModel.setCatList(tempList); } @Override public void onCancelled(@NonNull DatabaseError databaseError) { throw databaseError.toException(); } }); }
- 在第二个Fragment中监听ViewModel的数据
private SharedViewModel sharedViewModel; // 在onViewCreated生命周期中初始化 sharedViewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class); // 监听列表变化,只要数据更新就会回调 sharedViewModel.getCatList().observe(getViewLifecycleOwner(), catList -> { // 这里直接拿到最新的列表,不需要主动调用Dashboard的方法 System.out.println(catList.size()); // 后续处理列表的逻辑写在这里 });
方案2:通过宿主Activity中转
如果不想用ViewModel,也可以让两个Fragment的共同宿主Activity持有列表,或者持有Dashboard的实例:
- 在宿主Activity中定义公共方法返回Dashboard实例
// 宿主Activity中 public Dashboard getDashboardFragment() { // 如果你是用ViewPager或者导航组件的话,对应调整获取Fragment的方式 return (Dashboard) getSupportFragmentManager().findFragmentByTag("dashboard_tag"); }
- 第二个Fragment中先从Activity获取Dashboard实例再调用方法
// 第二个Fragment中 Dashboard db = ((你的宿主Activity类名) requireActivity()).getDashboardFragment(); if (db != null) { List<Catergory_List> TExpenses= db.TrasactionExpenses(); System.out.println(TExpenses.size()); }
注意:这个方案还是需要你自己处理Firebase异步加载的问题,确保调用方法时数据已经加载完成
额外提示
注意代码里的类名、方法名存在拼写错误(Catergory应为Category,Trasaction应为Transaction),建议统一修正避免后续开发出错。
内容的提问来源于stack exchange,提问作者Android God
相关产品推荐
相关产品推荐

