本文讲解的主要是通过预处理布局来解决ListView和RecyclerView的卡顿问题。
ListView与RecyclerView的卡顿我将之分为两个阶段:
1) 绑定数据阶段
这个阶段优化网上有很多说法,也已经被大家所熟知。 比如: 图片通过框架延迟加载,懒加载; 禁止在这里做耗时操作, 如: findViewById , 创建对象, 处理业务逻辑, 处理复杂的计算逻辑等;
2) 初始化layout阶段
本文重点介绍的是这个阶段的优化, 有人会问, ListView通过viewHolder 通过判定convertView == null 这个不是固化的操作吗, 还有啥优化空间? 还能避免这一步??? RecyclerView 也是一样。
答案当然是否定的。 是的, 我们不能避免这些固化的写法, 不能避免不去创建inflate layout . 那这个阶段还有啥可以优化的呢???
首先我要提出问题所在: 在ListView和RecyclerView被加载出来显示之后, 再滑动会出现卡顿, 而后就顺畅多了, 问题是显示之后, 在滑动为啥会卡顿呢 ??
RecyclerView 虽然比ListView灵活的多, 但是滚动时的卡顿确比ListView更明显, 有些人有疑问 :这难道不是绑定数据造成的吗? 其实不然。 是在滚动时会额外通过getView或者onCreateViewHolder 里面继续inflate.layout造成的。 很多有又有疑问, 为啥我没有这个感觉呢?? 那是因为很多layout不复杂的情况下效果很轻微, 但是如果你设置了header, 第一屏幕显示的都是header view , 而list是从第2页屏幕开始显示的呢??? 你有试过吗, 如果试过或者知道它们的缓存原理就会发现, 再RecyclerView或者ListView被显示出来的时候, getView或者onCreateViewHolder 并没有被执行, 或者执行很少, 只有在滚动时才获取执行, 然后就造成了卡顿。 那是因为它们的缓存机制导致, 初始化只加载可视范围内的item (这里不细细谈到它们的缓存机制,如果需要验证, 那么请在getView 或者onCreateViewHolder 哪里添加打印) 。 而滚动时inflate.layout 如果不复杂可能10ms就解决了, 你还能流程的体验, 但是如果复杂, 那么就会体验到滚动开始有轻微的卡顿(丢帧) , 知道它们的缓存机制完全足以支撑你的滚动, 不再去重新inflate.layout 。
说了这么多, 没有解决办法, 然并卵 ?
ListView 的预处理加载item , 也就是让它多加载几个item , 使之滚动的时候, 不去创建layout , 而是使用缓存好的item 。
Method method = ShareReflectUtil.findMethod(this,”addViewBelow”,View.class, int.class);
intposition = getLastVisiblePosition();
View view = getChildAt(position);
for(inti =0;i < size;i++) {
method.invoke(this,view,i + position);
}
RecyclerView的处理办法:
RecyclerView.RecycledViewPool pool = recyclerView.getRecycledViewPool();
pool.setMaxRecycledViews(viewType,count);
for(intindex =0;index < count;index++) {
pool.putRecycledView(recyclerView.getAdapter().createViewHolder(recyclerView,0));
}
注意一定要在setAdapter之后调用, 否者无效, 因为setAdapter时会清除你的pool缓存。