对于列表,不管用RecyclerView 还是ListView,我们都会用ViewHolder来复用布局。但是,即使这样做了,还是会出现卡顿。
这时候我们就需要分析卡顿的原因是什么?为什么别人写的不卡?为什么很多商店的app都有卡顿?
卡顿的原因:
1.产品设计不合理导致卡片布局过度复杂,产品只追求界面的高大上,而忽略了实现上的复杂度。
2.卡顿的另一个最大原因是图片的加载,如果图片过大,卡顿甚至崩溃都不是问题。即使图片使用了压缩后的,并且用了Fresco等图片加载框架,发现还是会有卡顿。虽然图片是异步加载的,但是图片的加载都伴随着三级缓存,图片IO会导致卡
经过以上1,2分析,然后就开始考虑该怎么去优化呢?如果产品的需求改变不了,那就要另辟蹊径了。也就是主要的优化集中在复杂布局和图片加载。
复杂布局的优化:
1.尽量减少布局嵌套,层级越深,每次测量时间久越久。
2. 如果布局很复杂,可以考虑自定义布局能不能实现。
3.尽量减少过度绘制区域。这个可以在开发者选项中看到:调试GPU过度绘制。
图片加载的优化,不仅仅是图片加载,应该说是列表在滚动过程中,如果布局很复杂,而且样式也很多,那就需要考虑滚动的时候不做复杂布局及图片的加载,尽量减少滚动过程中的耗时操作,这样滚动停止的时候再加载可见区域的布局,因为这个时候是停止状态,即使略微耗时一些用户的感知也是比较小的,就会给人一种不卡的假象。
对于列表滚动过程中,卡顿的判断可以打开开发者选项中的:GPU呈现模式分析->在屏幕上显示为条形图。就可以直观的看到滑动过程中有没有卡顿了。
先上一些关键代码吧:
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
/**
* Created by lk on 16/7/12.
*/
public class PWRecyclerView extends RecyclerView {
private OnScrolledLinstener onScrolledLinstener;
private BaseAdapter adapter;
private LayoutManager layout;
public PWRecyclerView(Context context) {
this(context, null);
}
public PWRecyclerView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public PWRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
addOnScrollListener(new ImageAutoLoadScrollListener());
}
@Override
public void setLayoutManager(LayoutManager layout) {
this.layout = layout;
super.setLayoutManager(layout);
}
@Override
public void setAdapter(Adapter adapter) {
if(adapter instanceof BaseAdapter) {
this.adapter = (BaseAdapter) adapter;
}
super.setAdapter(adapter);
}
public class ImageAutoLoadScrollListener extends OnScrollListener{
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if(onScrolledLinstener != null){
onScrolledLinstener.onScrolled(recyclerView, dx, dy);
}
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
switch (newState){
case SCROLL_STATE_IDLE: // The RecyclerView is not currently scrolling.
//对于滚动不加载图片的尝试
adapter.setScrolling(false);
adapter.notifyDataSetChanged();
break;
case SCROLL_STATE_DRAGGING: // The RecyclerView is currently being dragged by outside input such as user touch input.
adapter.setScrolling(false);
break;
case SCROLL_STATE_SETTLING: // The RecyclerView is currently animating to a final position while not under
adapter.setScrolling(true);
break;
}
}
}
public void setOnScrollLinstener(OnScrolledLinstener onScrolledLinstener){
this.onScrolledLinstener = onScrolledLinstener;
}
public interface OnScrolledLinstener{
void onScrolled(RecyclerView recyclerView, int dx, int dy);
}
}
主要就是对onScrollStateChanged方法进行监听,然后通知adapter是否加载图片或复杂布局。
对于复杂布局的优化效果还是很明显的。
如果读者有更好的方法,请不吝赐教。
下面是基于此文进行的进一步优化