Android MVVM架构下两个同布局RecyclerView数据异常求助
解决两个RecyclerView共享/显示数据异常的问题
我来帮你梳理下问题的根源,然后一步步给出可行的解决方案:
问题核心分析
你遇到的问题本质上是数据集共享/覆盖以及LiveData异步处理错误导致的:
- 最初用同一个
UnsortedAdapter实例给两个RecyclerView,两次调用setData会直接覆盖Adapter内部的数据集,所以两个列表最终都会显示最后一次设置的数据。 - 后续尝试的方案中,Repository里用
AsyncTask.get()同步获取LiveData的方式是错误的——Room的Dao返回LiveData时会自动在后台执行查询,不需要手动用AsyncTask包裹,这种同步获取会阻塞主线程,导致LiveData无法正确触发生命周期绑定,进而出现数据不显示的问题。
可行解决方案
1. 复用原Adapter,创建两个独立实例
因为两个RecyclerView的布局和绑定逻辑完全一致,只是数据源不同,不需要新建UnsortedAdapter2,只需要创建两个UnsortedAdapter的独立实例即可,每个实例维护自己的数据集。
2. 修正Repository和ViewModel的LiveData逻辑
首先修改UnsortedRepository,去掉错误的AsyncTask包裹:
public class UnsortedRepository { private UnsortedDao unsortedDao; private LiveData<List<Unsorted>> allUnsorted; public UnsortedRepository(Application application){ UnsortedDatabase database = UnsortedDatabase.getInstance(application); unsortedDao = database.unsortedDao(); allUnsorted = unsortedDao.getAllUnsorted(); } // 直接返回Dao的LiveData,Room会自动在后台执行查询 public LiveData<List<Unsorted>> getUnsortedWhereDateIs(String currentDate) { return unsortedDao.getUnsortedWhereDateIs(currentDate); } }
然后简化UnsortedViewModel的对应方法:
public class UnsortedViewModel extends AndroidViewModel { // ... 其他代码不变 public LiveData<List<Unsorted>> getUnsortedWhereDateIs(String currentDate) { return repository.getUnsortedWhereDateIs(currentDate); } // ... 其他代码不变 }
3. Activity中正确初始化并绑定数据
在Activity中创建两个独立的Adapter,分别绑定到对应的RecyclerView,然后观察LiveData并分别处理数据源:
// 初始化两个独立的Adapter实例 final UnsortedAdapter eatFrogAdapter = new UnsortedAdapter(); final UnsortedAdapter rhythmsAdapter = new UnsortedAdapter(); // 配置第一个RecyclerView eatFrog.setHasFixedSize(true); eatFrog.setLayoutManager(new LinearLayoutManager(this)); eatFrog.setAdapter(eatFrogAdapter); // 配置第二个RecyclerView biologicalRhythms.setHasFixedSize(true); biologicalRhythms.setLayoutManager(new LinearLayoutManager(this)); biologicalRhythms.setAdapter(rhythmsAdapter); // 观察数据源,分别处理并设置给对应Adapter viewModel.getUnsortedWhereDateIs(currentDate).observe(this, unsortedList -> { if (unsortedList == null) return; // 处理第一个列表的数据 List<Unsorted> eatFrogData = EatAFrog(unsortedList); eatFrogAdapter.setData(eatFrogData); eatAFrogList = eatFrogData; // 处理第二个列表的数据 List<Unsorted> rhythmsData = BiologicalRhythms(unsortedList); rhythmsAdapter.setData(rhythmsData); biologicalList = rhythmsData; });
4. 优化Adapter的setData方法(可选)
为了避免直接替换列表引用可能带来的问题,可以优化setData方法:
public void setData(List<Unsorted> unsortedList){ this.list.clear(); this.list.addAll(unsortedList); notifyDataSetChanged(); }
额外MVVM架构优化建议
按照MVVM的职责分离原则,数据处理逻辑应该放在ViewModel中,而不是Activity。可以在ViewModel中提前处理好两个数据集,暴露对应的LiveData给Activity观察:
在ViewModel中添加:
private final MutableLiveData<List<Unsorted>> eatFrogLiveData = new MutableLiveData<>(); private final MutableLiveData<List<Unsorted>> rhythmsLiveData = new MutableLiveData<>(); public LiveData<List<Unsorted>> getEatFrogLiveData() { return eatFrogLiveData; } public LiveData<List<Unsorted>> getRhythmsLiveData() { return rhythmsLiveData; } public void loadTasksByDate(String currentDate) { repository.getUnsortedWhereDateIs(currentDate).observeForever(unsortedList -> { if (unsortedList != null) { eatFrogLiveData.setValue(EatAFrog(unsortedList)); rhythmsLiveData.setValue(BiologicalRhythms(unsortedList)); } }); }
然后Activity中只需要观察对应LiveData:
viewModel.loadTasksByDate(currentDate); viewModel.getEatFrogLiveData().observe(this, eatFrogData -> { eatFrogAdapter.setData(eatFrogData); eatAFrogList = eatFrogData; }); viewModel.getRhythmsLiveData().observe(this, rhythmsData -> { rhythmsAdapter.setData(rhythmsData); biologicalList = rhythmsData; });
这样Activity的代码更简洁,ViewModel承担了数据处理的职责,完全符合MVVM的架构设计。
内容的提问来源于stack exchange,提问作者Alisa Petrova
相关产品推荐
相关产品推荐

