同时,我编写了一个自定义适配器,可以添加页眉和页脚。我使用了这个适配器,并添加了一个加载更多页脚,这样我的列表在向下滚动时可以加载更多。这导致了一点:我的列表,可以加载更多,将始终包含至少一个项目(加载更多页脚)。
为避免误解,下面的“项目”一词将特别表示项目不是页眉或页脚。
然后,当我通过diffUtil将项目从n(n>0)项通知为零时,问题发生了,我的应用程序崩溃。
值得一提的是,如果我使用没有页眉或页脚的自定义适配器,一切都会好的。
我一直在寻找解决办法,但他们的情况对我来说都不一样。
下面是自定义适配器的代码(Java),diffUtil将更新调度到其中的innerAdapter:
public class WrapperAdapter extends RecyclerView.Adapter {
// 0x40000000 为 1位 flag 位,1为 HEADER ,0 为 FOOTER
private static final int HEADER_FOOTER_TYPE_MASK = 0x40000000;
// 0x3f0000 为 6位 index 位,对应的 HEADER FOOTER 数组的 index ,也就是说最多保存64个 HEADER 、64个 FOOTER
private static final int HEADER_FOOTER_INDEX_MASK = 0x3f000000;
// 后面的 24 位为 view 的 hash code 位,可以保证每个 HEADER、FOOTER 都能有不同的 viewType
private static final int HEADER_FOOTER_HASH_MASK = 0x00ffffff;
private RecyclerView.Adapter innerAdapter;
private RecyclerView.AdapterDataObserver innerObserver = new AdapterDataObserverProxy();
private List<View> headers = new ArrayList<>();
private List<View> footers = new ArrayList<>();
public WrapperAdapter(@NonNull RecyclerView.Adapter adapter) {
innerAdapter = adapter;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType < 0) {
if ((viewType & HEADER_FOOTER_TYPE_MASK) != 0) {
// HEADER
int headerIndex = (viewType & HEADER_FOOTER_INDEX_MASK) >> 24;
return new InnerViewHolder(headers.get(headerIndex));
} else {
// FOOTER
int footerIndex = (viewType & HEADER_FOOTER_INDEX_MASK) >> 24;
return new InnerViewHolder(footers.get(footerIndex));
}
}
return innerAdapter.onCreateViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (isHeader(position) || isFooter(position)) {
return;
}
innerAdapter.onBindViewHolder(holder, position - headers.size());
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List payloads) {
if (isHeader(position) || isFooter(position)) {
return;
}
innerAdapter.onBindViewHolder(holder, position - headers.size(), payloads);
}
@Override
public int getItemViewType(int position) {
if (isHeader(position)) {
return Integer.MIN_VALUE | HEADER_FOOTER_TYPE_MASK | ((position & (HEADER_FOOTER_INDEX_MASK >> 24)) << 24) | (headers.get(position).hashCode() & HEADER_FOOTER_HASH_MASK);
}
if (isFooter(position)) {
int footerIndex = position - innerAdapter.getItemCount() - headers.size();
return Integer.MIN_VALUE | ((footerIndex & (HEADER_FOOTER_INDEX_MASK >> 24)) << 24) | (footers.get(footerIndex).hashCode() & HEADER_FOOTER_HASH_MASK);
}
int innerViewType = innerAdapter.getItemViewType(position - headers.size());
if (innerViewType < 0) {
throw new IllegalArgumentException("View type cannot be negative, which is claimed by HEADER and FOOTER");
}
return innerViewType;
}
@Override
public int getItemCount() {
if (innerAdapter.getItemCount() == 0) {
return headers.size();
} else {
return innerAdapter.getItemCount() + headers.size() + footers.size();
}
}
private boolean isHeader(int position) {
return position < headers.size();
}
private boolean isFooter(int position) {
return position > getItemCount() - footers.size() - 1;
}
private class InnerViewHolder extends RecyclerView.ViewHolder {
InnerViewHolder(@NonNull View itemView) {
super(itemView);
}
}
public void addHeader(@NonNull View header) {
if (!headers.contains(header)) {
headers.add(header);
notifyItemInserted(headers.size() - 1);
}
}
public void removeHeader(@NonNull View header) {
if (headers.contains(header)) {
int index = headers.indexOf(header);
headers.remove(index);
notifyItemRemoved(index);
}
}
public void addFooter(@NonNull View footer) {
if (!footers.contains(footer)) {
footers.add(footer);
notifyItemInserted(getItemCount() - 1);
}
}
public void removeFooter(@NonNull View footer) {
if (footers.contains(footer)) {
int index = footers.indexOf(footer);
footers.remove(index);
notifyItemRemoved(headers.size() + innerAdapter.getItemCount() + index);
}
}
@Override
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
if (holder instanceof InnerViewHolder) {
super.onViewRecycled(holder);
} else {
innerAdapter.onViewRecycled(holder);
}
}
@Override
public boolean onFailedToRecycleView(@NonNull RecyclerView.ViewHolder holder) {
if (holder instanceof InnerViewHolder) {
return super.onFailedToRecycleView(holder);
} else {
return innerAdapter.onFailedToRecycleView(holder);
}
}
@Override
public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) {
if (holder instanceof InnerViewHolder) {
super.onViewAttachedToWindow(holder);
} else {
innerAdapter.onViewAttachedToWindow(holder);
}
}
@Override
public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) {
if (holder instanceof InnerViewHolder) {
super.onViewDetachedFromWindow(holder);
} else {
innerAdapter.onViewDetachedFromWindow(holder);
}
}
@Override
public void registerAdapterDataObserver(@NonNull RecyclerView.AdapterDataObserver observer) {
super.registerAdapterDataObserver(observer);
innerAdapter.registerAdapterDataObserver(innerObserver);
}
@Override
public void unregisterAdapterDataObserver(@NonNull RecyclerView.AdapterDataObserver observer) {
super.unregisterAdapterDataObserver(observer);
innerAdapter.unregisterAdapterDataObserver(innerObserver);
}
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
innerAdapter.onAttachedToRecyclerView(recyclerView);
}
@Override
public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
innerAdapter.onDetachedFromRecyclerView(recyclerView);
}
@Override
public void setHasStableIds(boolean hasStableIds) {
super.setHasStableIds(hasStableIds);
innerAdapter.setHasStableIds(hasStableIds);
}
@Override
public long getItemId(int position) {
if (isHeader(position)) return super.getItemId(position);
if (isFooter(position)) return super.getItemId(position);
return innerAdapter.getItemId(position);
}
private class AdapterDataObserverProxy extends RecyclerView.AdapterDataObserver {
@Override
public void onChanged() {
WrapperAdapter.this.notifyDataSetChanged();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
WrapperAdapter.this.notifyItemRangeChanged(positionStart + WrapperAdapter.this.headers.size(), itemCount);
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
WrapperAdapter.this.notifyItemRangeChanged(positionStart + WrapperAdapter.this.headers.size(), itemCount, payload);
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
WrapperAdapter.this.notifyItemRangeInserted(positionStart + WrapperAdapter.this.headers.size(), itemCount);
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
WrapperAdapter.this.notifyItemRangeRemoved(positionStart + WrapperAdapter.this.headers.size(), itemCount);
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
WrapperAdapter.this.notifyItemMoved(fromPosition + WrapperAdapter.this.headers.size(), toPosition + WrapperAdapter.this.headers.size());
}
}
}
private var wrapperAdapter: WrapperAdapter? = null
override fun setAdapter(adapter: Adapter<*>?) {
wrapperAdapter = if (adapter != null) {
WrapperAdapter(adapter)
} else {
null
}
super.setAdapter(wrapperAdapter)
}
fun addHeader(header: View) {
wrapperAdapter?.addHeader(header)
}
fun addFooter(footer: View) {
wrapperAdapter?.addFooter(footer)
}
fun removeHeader(header: View) {
wrapperAdapter?.removeHeader(header)
}
fun removeFooter(footer: View) {
wrapperAdapter?.removeFooter(footer)
}
从GetItemCount()
的实现来看,似乎只有在有项目时才显示页脚。删除最后一个项时,必须通知包装适配器页脚也已删除。
假设有2个页眉,1个项目,3个页脚:GetItemCount()
返回6。如果删除内部项,则仅从内部适配器传播1个删除,但GetItemCount()
现在返回2而不是预期的5
我建议修改AdapterDataObserverProxy
:
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
WrapperAdapter.this.notifyItemRangeRemoved(positionStart + WrapperAdapter.this.headers.size(), itemCount);
if (itemCount > 0 && innerAdapter.getItemCount() == 0 && footers.size() > 0) {
// no more inner items, notify the removal of the footers
int firstFooterPosition = headers.size();
int footerCount = footers.size();
WrapperAdapter.this.notifyItemRangeRemoved(firstFooterPosition, footerCount);
}
}
我正在使用Android应用程序,我想以某种方式打印HashMap的键和值。假设以下是HashMap的内容: 我想以这样一种方式打印HashMap键和值,即字母键首先按字母顺序打印,然后是数字键按升序打印: 我现在做的是: > < li> 获取密钥集并将其保存到数组列表中 使用比较器对数组列表进行排序 使用排序列表打印出地图中的值 这是我的代码: 到目前为止,它还在工作,但是在某些情况下,我没有得
我有一个RxJava2可观察到,它接受两个列表,为它们计算diff结果,并将此数据发送到适配器。适配器在主线程上调度更新。 我检测到不一致。在某些设备上有时出现无效视图保持器适配器PositionViewHolder错误。我也搞不清我的代码出了什么问题。最小SDK 21,目标SDK 26,RecyclerView版本为26.0.0。我知道扩展LinearLayoutManager和静默捕获此错误的
我有一个问题,我在这里了解到错误已被修复,我应该确保我在主线程上插入数据并调用适当的通知。我这样做了,但我仍然得到这个异常。 onLoadFinisher方法(我正在使用加载器加载更多数据) 日志
我有以下一段代码: 这是我得到的错误: 还有这个: 我错过了什么?
我想在第12版discord.js一个系统,如果你的状态中有我的虚荣邀请,你就会得到一个支持者的角色 每当我尝试此操作时,它总是说 这是我的密码
我使用Reactjs作为前端。我想从javascript端检索自定义属性。就像这个答案所说的。 https://stackoverflow.com/a/32890003/2940265 但我找不到如何在javascript端实现它。 我在Chrome中进行了调试,但找不到适合自定义属性的结果。 请帮帮忙