感谢开源项目作者 BaseRecyclerViewAdapterHelper解决了写复杂的RecyclerView的Adapter问题。但是目前遇到一个问题无法解决: 正常的RecyclerView设置setEnptyView之后能正常显示,但是如果是这个RecyclerView设置了HeaderView之后,因为监听的是列表数据的变化,就会出现头部数据变化了之后,调用notifyDataSetChanged更改数据时无反应。
问题分析,因为setEmptyView方法是针对整个RecyclerView界面设置的,但是数据监听的是列表数据的变化,当你给这个RecyclerView添加一个HeaderView之后,头部数据的变化没有被监听导致的。但是我们可以给列表添加一条假数据来达到数据变化的效果,从而更新界面刷新。但是这样也会有个问题。就是当头部的数据删除了,列表的数据也变化了,却没有办法再setEmptyView了,这样就还是没有从根本上解决问题。也尝试过从RecyclerView拆分头部布局和列表,但是发现实现的效果不是预期的效果。
后来发现开源项目提供了有个可以设置多个item效果的Adapter:BaseSectionMultiItemQuickAdapter,这个adapter可以根据界面显示的数据不同设置不同的ItemType,然后在Adapter里面根据ItemType来设置数据。这个多个Iteml类型的界面主要就是界面的数据需要有序,但是目前我们只是数据增加了一个头部,其他的数据还是一个头部,然后头部下面是一个列表,如下图:
然后仔细想想我的实现方式并没有问题,就是选择BaseSectionQuickAdapter实现一个带头部的列表集合,然后增加一个头部,刷新在顶部。如果改用BaseSectionMultiItemQuickAdapter并不是那种有规律的多种Item布局界面,所以需要解决的就是新增头部之后,setEmptyView之后头部数据刷新不更新的问题。
查看BaseRecyclerViewAdapterHelpe项目里的setEmptyView方法:
public void setEmptyView(View emptyView) {
int oldItemCount = getItemCount();
boolean insert = false;
if (mEmptyLayout == null) {
mEmptyLayout = new FrameLayout(emptyView.getContext());
final LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
final ViewGroup.LayoutParams lp = emptyView.getLayoutParams();
if (lp != null) {
layoutParams.width = lp.width;
layoutParams.height = lp.height;
}
mEmptyLayout.setLayoutParams(layoutParams);
insert = true;
}
mEmptyLayout.removeAllViews();
mEmptyLayout.addView(emptyView);
mIsUseEmpty = true;
if (insert && getEmptyViewCount() == 1) {
int position = 0;
if (mHeadAndEmptyEnable && getHeaderLayoutCount() != 0) {
position++;
}
if (getItemCount() > oldItemCount) {
notifyItemInserted(position);
} else {
notifyDataSetChanged();
}
}
}
然后发现BaseQuickAdapter里有个属性:
private boolean mIsUseEmpty = true;
字面的意思就是是否使用EmptyView布局,我们其实可以理解项目的布局是有三层布局的,首先就是一层加载框布局、然后是真正的数据显示布局、最后一层就是一层空数据显示布局,这样我们数据没有刷新的问题就可以理解为空数据的界面一直显示导致的。
@Override
public int getItemCount() {
int count;
if (1 == getEmptyViewCount()) {
count = 1;
if (mHeadAndEmptyEnable && getHeaderLayoutCount() != 0) {
count++;
}
if (mFootAndEmptyEnable && getFooterLayoutCount() != 0) {
count++;
}
} else {
count = getHeaderLayoutCount() + mData.size() + getFooterLayoutCount() + getLoadMoreViewCount();
}
return count;
}
我们发现getItemCount方法调用了getEmptyViewCount方法:
/**
* if show empty view will be return 1 or not will be return 0
*
* @return
*/
public int getEmptyViewCount() {
if (mEmptyLayout == null || mEmptyLayout.getChildCount() == 0) {
return 0;
}
if (!mIsUseEmpty) {
return 0;
}
if (mData.size() != 0) {
return 0;
}
return 1;
}
然后这个getEmptyViewCount方法又用到了mIsUseEmpty这个属性值来控制是否显示空布局。
所以我们就可以得到真正的解决方法:在数据更新的时候调用下面这个方法,就可以去掉空数据界面然后刷新出数据界面。
mWriteWorkAdapter.isUseEmpty(false)
当然,你会问是不是需要在setEmptyView的时候再把这个值设置为true?
其实是需要的,虽然setMeptyView源码里面已经默认把它设置成true了,但是我们还是需要在调用setMeptyView方法调用之前把这个值设置成true才能正确的设置空数据界面,否则空数据界面就会被追加到数据显示界面,导致数据显示错误。