Android RecycleView加载速度优化
Android开发中,经常会碰到列表加载优化的问题。之前是ListView,现在经常用到RecycleView;不管怎么换控件,优化的思路始终是一样的,那就是将当前的资源尽量都放在用户需要的地方,仅加载用户需要看到的,用户不会看到的我们不需要加载。
思路有好几个,第一种是实现一个和RecycleView加载页面算法一样的队列存储结构,这种实现起来的代码难度相对较大。
第二种就是根据不同的状态去加载,这种实现起来的难度相对较小。我选择第二种进行说明。
我的优化步骤如下,先以最小资源去加载数据;然后逐步去优化;
第一步,先仅仅在界面滑动静止时,去通知界面刷新,满足最基本的页面加载需求;
核心代码如下:
Adapter显示代码:
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
recycleList.onBindViewHolder(position);
if (holder instanceof Holder) {
final Holder h = (Holder) holder;
TableVo obj = recycleList.get(position);
h.image.setImageBitmap(null);
if (obj != null) {
h.view.setText(obj.getTitle());
h.image.setImageBitmap(recycleList.getBitmap(position));
}
}
}
数据管理类加载代码
@Override
public Bitmap getBitmap(int position) {
Bitmap bitmap = bitmapcache.get(position);
if (bitmap == null && RecyclerView.SCROLL_STATE_IDLE == callback.getScrollState()) {
loadBitmap(position);
}
return bitmap;
}
图片获取
private void loadBitmap(int position) {
TableVo vo = dataCache.get(position);
if (vo != null && bitmapcache.get(position) == null && !TextUtils.isEmpty(vo.getPath())) {
String path = vo.getPath();
Message message = bitmapHandler.obtainMessage();
message.what = position;
message.obj = path;
bitmapHandler.sendMessage(message);
}
}
//模拟图片加载
bitmapHandler = new Handler(bitmapThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
int position = msg.what;
if (taskSet.contains(position)) {
return;
}
taskSet.add(position);
String path = (String) msg.obj;
if (bitmapcache != null) {
Bitmap bitmap = bitmapcache.get(position);
if (bitmap == null) {
try {
bitmap = BitmapUtils.load(path);
bitmapcache.put(position, bitmap);
taskSet.remove(position);
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
if (bitmap != null) {
LruRecycleData.this.callback.updataposition(position);
}
}
super.handleMessage(msg);
}
};
//当滑动静止时,主动去通知界面刷新
@Override
public void onScrollStateChanged(int newState) {
if (RecyclerView.SCROLL_STATE_IDLE == newState) {
for (int i = callback.getFirstVisablePosition(); i <= callback.getLastVisablePosition(); i++) {
loadBitmap(i);
}
}
}
完成以上的代码。就可以满足仅仅加载用户需要看到的;也就是仅仅在页面静止时去加载数据;taskSet和bitmapcache可以保证不会重复去加载图片;
可是上面的有个问题,就是当你慢慢滑动时,新页面也是静止时才开始加载,这样速度就显得有些慢了;
因此我对这个静止加载的思路进行了一个优化,将静止的条件扩大为当慢慢滑动时,也就是滑动速度在一个范围内时,就可以去加载图片;因此我优化了一下,慢速滑动的情况,代码如下:
//即将要进入的界面
@Override
public void onViewAttachedToWindow(int position) {
attachPosition = position;
load(position);
}
//处理慢速滑动时的
@Override
public void onScrolled(int dx, int dy) {
System.arraycopy(dys, 1, dys, 0, 1);
dys[1] = Math.abs(dy);
if (dys[1] < MOVE_SLOW_FLAG && ((dys[0] >= dys[1]) || dys[0] < MOVE_SLOW_FLAG)) {
loadBitmap(attachPosition);
}
}
这样下来,我们就可以达到最大化的优化列表加载数据的速度了。