1、Crash异常信息
最近在公司项目中开始使用RecycleView,报了一个Crash:
2、原因分析
我的项目中遇到的问题是,在下载管理器的下载中tab里,当某个应用下载完毕时,从下载列表中remove移除这个item,会报Inconsistency detected的错误而导致程序崩溃。
" Inconsistency detected. Invalid view holder adapter"的大概意思就是 数据不一致,无效的视图适配器。
以下是项目中导致crash的方法:
public void removeData(T data) {
if (data != null) {
int position = getItemPosition(data);
if(position!=-1){
this.mDatas.remove(position);
}
}
}
mDatas是数据源 ArrayList,推测:数据源的这条数据被移除了,但是并没有刷新 Apdater视图,所以导致崩溃?
3、解决方案
3.1 notifyItemRemoved(position)
于是在移除item的时候加上刷新Recycleview Adapter的一行代码notifyItemRemoved(position);
public void removeData(T data) {
if (data != null) {
int position = getItemPosition(data);
if(position!=-1){
this.mDatas.remove(position);
notifyItemRemoved(position);//如果少了这一句,会报Inconsistency detected异常而崩溃
}
}
}
运行程序,尝试复现问题,果然发现正常了。
所以,在进行数据移除时,务必要保证RecyclerView.Adapter中的数据和移除的数据源保持一致!
3.2 直接捕获这个异常
- 创建一个类WrapContentGridLayoutManager继承GridLayoutManager,重写onLayoutChildren方法
*
* 为了解决RecyclerView的官方bug:Inconsistency detected. Invalid view holder adapter
*/
public class WrapContentGridLayoutManager extends GridLayoutManager {
public WrapContentGridLayoutManager(Context context, int spanCount) {
super(context, spanCount);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
}catch (IndexOutOfBoundsException e){
//手动catch住
e.printStackTrace();
DebugLog.d("WrapContentGridLayoutManager","手动捕获异常:"+e.getMessage());
}
}
}
- 设置RecyclerView的布局管理为WrapContentGridLayoutManager对象
rv = (RecyclerView) view.findViewById(R.id.app_recycler_view);
rv.setLayoutManager(new WrapContentGridLayoutManager(mContext,6));
其实手动捕获catch住这个异常 并不是什么好的解决方法,但是我更新到最新的V7包下RecyclerView控件,发现官方也还是没有修复这个bug,所以也只能暂时这么处理了。
4、参考
https://code.google.com/p/android/issues/detail?id=77846(google官方group讨论组里有提到)