LiveData仅首次通知PagedList变更,加载更多后无通知问题咨询
嘿,我之前也踩过Paging Library结合LiveData时更新不触发观察者的坑,咱们一步步来拆解问题、解决它:
你遇到的情况是LiveDataDataSource的失效机制来自动更新PagedList并通知LiveData。
1. 检查ViewModel中PagedList的创建方式
一定要用LivePagedListBuilder创建LiveData
public class MyViewModel extends ViewModel { private LiveData<PagedList<Integer>> mPagedListLiveData; private MyDataSourceFactory mDataSourceFactory; public LiveData<PagedList<Integer>> getPagedList() { if (mPagedListLiveData == null) { // 配置分页参数 PagedList.Config config = new PagedList.Config.Builder() .setPageSize(10) // 每页数据量 .setPrefetchDistance(5) // 提前加载的距离 .setEnablePlaceholders(false) // 关闭占位符(避免空数据问题) .build(); mDataSourceFactory = new MyDataSourceFactory(); // 关键:用LivePagedListBuilder创建LiveData,它会自动监听DataSource的变化 mPagedListLiveData = new LivePagedListBuilder<>(mDataSourceFactory, config).build(); } return mPagedListLiveData; } }
❌ 错误做法:手动创建LiveData并直接赋值新的PagedList,比如mPagedListLiveData.setValue(newPagedList)——旧观察者绑定的是原来的LiveData实例,自然收不到新数据的通知。
2. 确保DataSource的更新逻辑正确
如果是自定义DataSource,每次数据更新后必须调用invalidate()方法,这是触发PagedList更新的关键信号:
public class MyDataSource extends PageKeyedDataSource<Integer, Integer> { private List<Integer> mData = new ArrayList<>(); // 手动触发加载更多的方法(供Activity按钮调用) public void loadMore() { // 模拟获取新数据 List<Integer> newData = fetchNextPageData(); mData.addAll(newData); // 关键:通知DataSource失效,触发PagedList更新 invalidate(); } // 以下是分页加载的默认实现 @Override public void loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<Integer, Integer> callback) { mData.addAll(fetchInitialData()); callback.onResult(mData, null, 2); } @Override public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, Integer> callback) { List<Integer> newData = fetchNextPageData(); mData.addAll(newData); callback.onResult(newData, params.key + 1); } @Override public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, Integer> callback) { // 不需要加载前页的话空实现即可 } // 模拟数据获取 private List<Integer> fetchInitialData() { /* ... */ } private List<Integer> fetchNextPageData() { /* ... */ } }
另外,你的DataSourceFactory要能拿到当前的DataSource实例,方便触发invalidate():
public class MyDataSourceFactory extends DataSource.Factory<Integer, Integer> { private MyDataSource mDataSource; @NonNull @Override public DataSource<Integer, Integer> create() { mDataSource = new MyDataSource(); return mDataSource; } public MyDataSource getCurrentDataSource() { return mDataSource; } }
3. 简化Activity中的观察者逻辑
观察者只需要注册一次,不要在按钮点击时重复注册:
public class MainActivity extends AppCompatActivity { private MyViewModel mViewModel; private MyAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mViewModel = ViewModelProviders.of(this).get(MyViewModel.class); mAdapter = new MyAdapter(); RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.setAdapter(mAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); // 仅注册一次观察者 mViewModel.getPagedList().observe(this, integers -> { // 用PagingAdapter的submitList方法更新数据 mAdapter.submitList(integers); Log.d("MainActivity", "PagedList更新,当前数据量:" + integers.size()); }); // 加载更多按钮点击事件 findViewById(R.id.btn_load_more).setOnClickListener(v -> { // 通知ViewModel触发加载更多 MyDataSource dataSource = mViewModel.getDataSourceFactory().getCurrentDataSource(); if (dataSource != null) { dataSource.loadMore(); } }); } }
Paging Library的LiveData更新逻辑是:数据变化 → 调用DataSource.invalidate() → LivePagedListBuilder自动创建新的DataSource → 生成新的PagedList → LiveData通知观察者
只要遵循这个流程,就能保证观察者能收到每次数据更新的通知。
内容的提问来源于stack exchange,提问作者Vahid18u

