无法使用android Paging库加载下一个数据

时间:2018-11-14 10:14:12

标签: android android-room android-livedata androidx android-paging

我正在尝试使用Room-Paging-LiveData-ViewModel显示呼叫日志列表。 没有分页,我的代码可以完美地工作。我也想使用分页。

在我的数据库中,我总共有25条通话记录。前9个通话记录显示在列表中。

通过调试,我发现通过Dao在视图模型中读取数据时,它返回的是大小为25的列表。但是,只有其中的前9个非null。列表中的所有其他条目均为空。

  

我希望空数据在被分页后将立即刷新   清单。但是问题是null永远不会被刷新   有效数据。

视图模型的observe方法仅被调用一次,仅第一次被调用。

我认为我做错了什么。

这是下面的代码

  

片段

public class CallLogListFragment extends Fragment {
    private static final String TAG = "RecentCallsFragment";

    public static String getTAG() {
        return TAG;
    }

    public static Fragment newInstance() {
        return new CallLogListFragment();
    }

    public CallLogListFragment() {
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        FragmentCallLogListBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_call_log_list, container, false);
        CallLogListAdapter adapter = new CallLogListAdapter();
        binding.list.setAdapter(adapter);
        CallLogListViewModel model = ViewModelProviders.of(this).get(CallLogListViewModel.class);
        model.getCallLogList().observe(this, adapter::refreshData);
        return binding.getRoot();
    }

}
  

适配器

public class CallLogListAdapter extends PagedListAdapter<CallLogItem, CallLogListAdapter.ViewHolder> {
    CallLogListAdapter() {
        super(DIFF_CALLBACK);
    }

    void refreshData(List<CallLogItem> data) {
        DiffUtil.DiffResult calculatedDiff = DiffUtil.calculateDiff(new CallLogListDiffUtilCallBack(this.data, data));
        this.data.clear();
        this.data.addAll(data);
        calculatedDiff.dispatchUpdatesTo(this);
    }

    private List<CallLogItem> data = new ArrayList<>();

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new ViewHolder(DataBindingUtil.inflate(
                LayoutInflater.from(parent.getContext()),
                R.layout.call_log_list_single_item,
                parent, false
        ));
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        CallLogItem item = data.get(position);
        holder.binding.setCallLog(item);
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder {
        public CallLogListSingleItemBinding binding;
        public ViewHolder(@NonNull CallLogListSingleItemBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }

     private static DiffUtil.ItemCallback<CallLogItem> DIFF_CALLBACK =
        new DiffUtil.ItemCallback<CallLogItem>() {
            @Override
            public boolean areItemsTheSame(CallLogItem oldItem, CallLogItem newItem) {
                return oldItem.getHeaderDateVisibility() == newItem.getHeaderDateVisibility()
                        && oldItem.getCallId().equals(newItem.getCallId());
            }

            @Override
            public boolean areContentsTheSame(@NonNull CallLogItem oldItem, @NonNull CallLogItem newItem) {
                return areItemsTheSame(oldItem, newItem);
            }
        };
}
  

@Dao
public interface CallLogDao extends BaseDao<CallLog>{
    @Query("SELECT * FROM log")
    List<CallLog> getAll();

    @Query("SELECT * FROM log WHERE number=:number")
    CallLog findByName(String number);

    @Query("SELECT * FROM log order by date desc")
    LiveData<List<CallLog>> getAllLive();

    @Query("SELECT * FROM log order by date desc")
    DataSource.Factory<Integer, CallLog> getAllLivePaged();
}
  

ViewModel

public class CallLogListViewModel extends ViewModel {
    private LiveData<List<CallLogItem>> callLogList;

    public CallLogListViewModel() {
        callLogList = Transformations.map(new LivePagedListBuilder<>(AppDatabase.get().callLogDao().getAllLivePaged(), 3).build(), input -> {
            List<CallLogItem> list = new ArrayList<>();
            for (int i = 0; i < input.size(); i++) {
                boolean isHeader = true;
                CallLog callLog = input.get(i);
                if(callLog!=null) {
                    if (i > 0) {
                        CallLog previousCallLog = input.get(i - 1);
                        if(previousCallLog!=null) {
                            isHeader = TimeFormat.isDifferentDate(callLog.date, previousCallLog.date);
                        }
                    }
                    list.add(CallLogItem.Companion.from(callLog, isHeader));
                }
            }
            return list;
        });
    }

    LiveData<List<CallLogItem>> getCallLogList() {
        return callLogList;
    }
}

后来我尝试制作

private LiveData<List<CallLogItem>> callLogList; 

之类的分页列表
private LiveData<PagedList<CallLogItem>> callLogList; 

但是我没有找到适当的方法来转变成那个。

2 个答案:

答案 0 :(得分:2)

为了能够返回映射的PagedList,您应该知道DataSourceDataSource.Factory具有map()mapByPage()。 您可以使用mapByPage()而不是使用Transformation映射DataSource Factory项目,如下所示:

DataSource.Factory<Integer, CallLog> dataSourceFactoryCallLog = AppDatabase.get().callLogDao().getAllLivePaged();

DataSource.Factory<Integer, CallLogItem> dataSourceFactoryCallLogItem = dataSourceFactoryCallLog.mapByPage(input -> {
   List<CallLogItem> list = new ArrayList<>();
   for (int i = 0; i < input.size(); i++) {
       boolean isHeader = true;
       CallLog callLog = input.get(i);
       if(callLog!=null) {
           if (i > 0) {
               CallLog previousCallLog = input.get(i - 1);
               if(previousCallLog!=null) {
                   isHeader = TimeFormat.isDifferentDate(callLog.date, previousCallLog.date);
               }
           }
           list.add(CallLogItem.Companion.from(callLog, isHeader));
       }
   }
   return list;
 });

LiveData<PagedList<CallLogItem>> callLogItems = new LivePagedListBuilder<>(dataSourceFactoryCallLogItem, 3).build()

编辑

根据PagedList documentation

  

对于占位符,PagedList始终是数据集的完整大小。 get(N)返回数据集中的第N个项目;如果尚未加载,则返回null。

     

没有空的占位符,PagedList是已经加载的数据的子列表。 PagedList的大小是当前已加载项目的数量,而get(N)返回第N个已加载项目。这不一定是数据集中的第N个项目。

     

默认情况下启用占位符,但是可以通过两种方式禁用占位符。如果DataSource在初始加载时不对数据集进行计数,或者在构建setEnablePlaceholders(boolean)时将false传递给PagedList.Config,则禁用它们。

您只需要创建一个PagedList.Config并将其添加到LivePagedListBuilder实例中。

PagedList.Config pagedListConfig =
                (new PagedList.Config.Builder())
                        .setEnablePlaceholders(false)
                        .setPageSize(3).build();

LiveData<PagedList<CallLogItem>> callLogItems = new LivePagedListBuilder<>(dataSourceFactoryCallLogItem, pagedListConfig).build()

答案 1 :(得分:1)

对于页面列表适配器,有两件事要注意。  1.数据将在内部进行处理,无需声明任何数据结构即可手动处理数据。  2. submitList中有一个称为PagedListAdapter的默认方法。有必要通过该方法将页面列表提交给适配器。

  

修改后的适配器

public class CallLogListAdapter extends PagedListAdapter<CallLogItem, CallLogListAdapter.ViewHolder> {
    private Context context;
    CallLogListAdapter(Context context) {
        super(DIFF_CALLBACK);
        this.context = context;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new ViewHolder(DataBindingUtil.inflate(
                LayoutInflater.from(parent.getContext()),
                R.layout.call_log_list_single_item,
                parent, false
        ));
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        CallLogItem item = getItem(position);
        if (item != null) {
            holder.binding.setCallLog(item);
            ImageUtil.setImage(holder.binding.ivProfileImage, item.getImageUrl(), item.getName());
        } else {
            holder.binding.invalidateAll();
        }
    }


    class ViewHolder extends RecyclerView.ViewHolder {
        public CallLogListSingleItemBinding binding;

        public ViewHolder(@NonNull CallLogListSingleItemBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }

    private static DiffUtil.ItemCallback<CallLogItem> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<CallLogItem>() {
                @Override
                public boolean areItemsTheSame(CallLogItem oldItem, CallLogItem newItem) {
                    return oldItem.getHeaderDateVisibility() == newItem.getHeaderDateVisibility()
                            && oldItem.getCallId()!=null &&  oldItem.getCallId().equals(newItem.getCallId());
                }

                @Override
                public boolean areContentsTheSame(@NonNull CallLogItem oldItem, @NonNull CallLogItem newItem) {
                    return areItemsTheSame(oldItem, newItem);
                }
            };
}
  

已修改的数据传递到适配器

CallLogListViewModel model = ViewModelProviders.of(this).get(CallLogListViewModel.class);
model.getCallLogList().observe(this, adapter::submitList);