我正在尝试使用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;
但是我没有找到适当的方法来转变成那个。
答案 0 :(得分:2)
为了能够返回映射的PagedList
,您应该知道DataSource
和DataSource.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始终是数据集的完整大小。 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);