You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RecyclerView中VectorDrawable复用优化及Picasso加载适配问题咨询

解决RecyclerView中高效复用VectorDrawable + 让Picasso支持VectorDrawable的方案

嘿,这个场景我太熟悉了——RecyclerView里反复创建VectorDrawable确实会触发频繁GC,导致列表滑动掉帧,而且Picasso默认确实不支持VectorDrawable加载。给你几个实用的解决方案,按需选:

方案1:自定义Picasso RequestHandler,让它支持VectorDrawable

Picasso的扩展性很强,我们可以写一个自定义的RequestHandler来处理VectorDrawable资源,同时利用Picasso的内存缓存机制自动复用Drawable对象,不用自己管理缓存。

步骤如下:

  1. 实现自定义的VectorDrawableRequestHandler:
public class VectorDrawableRequestHandler extends RequestHandler {
    private static final String SCHEME = "res";

    @Override
    public boolean canHandleRequest(Request data) {
        // 处理以res://开头的Uri,比如res://com.your.package/2131230800
        return SCHEME.equals(data.uri.getScheme());
    }

    @Override
    public Result load(Request request, int networkPolicy) throws IOException {
        Context context = request.context;
        int resId = context.getResources().getIdentifier(
                request.uri.getLastPathSegment(),
                "drawable",
                context.getPackageName()
        );
        // 用ResourcesCompat加载,兼容旧版本,并且确保Drawable可复用
        Drawable drawable = ResourcesCompat.getDrawable(context.getResources(), resId, null);
        if (drawable == null) {
            throw new IOException("VectorDrawable not found for resId: " + resId);
        }
        return new Result(drawable, Picasso.LoadedFrom.MEMORY);
    }
}
  1. 在初始化Picasso的时候添加这个Handler:
Picasso picasso = new Picasso.Builder(context)
        .addRequestHandler(new VectorDrawableRequestHandler())
        .build();
// 如果用全局单例,替换默认的Picasso实例
Picasso.setSingletonInstance(picasso);
  1. 在Adapter里加载VectorDrawable:
// 构造res://格式的Uri,比如resId是R.drawable.ic_vector
Uri uri = Uri.parse("res://" + context.getPackageName() + "/" + R.drawable.ic_vector);
picasso.load(uri)
        .into(holder.imageView);

这样Picasso会自动缓存这个Drawable,下次加载直接复用,不用每次新建。

方案2:在Adapter中提前缓存VectorDrawable(适合少量Drawable场景)

如果你的VectorDrawable数量不多(比如只有几种类型的图标),直接在Adapter初始化时把所有需要的Drawable加载好,存在一个Map里,onBind的时候直接取,逻辑更简单。

示例代码:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private HashMap<Integer, Drawable> drawableCache;
    private Context context;

    public MyAdapter(Context context) {
        this.context = context;
        drawableCache = new HashMap<>();
        // 提前加载所有需要的VectorDrawable
        cacheDrawable(R.drawable.ic_vector_1);
        cacheDrawable(R.drawable.ic_vector_2);
        // ... 其他需要的resId
    }

    private void cacheDrawable(int resId) {
        Drawable drawable = ResourcesCompat.getDrawable(context.getResources(), resId, null);
        if (drawable != null) {
            // 确保Drawable可安全复用,避免创建副本
            drawable.mutate().clearMutated();
            drawableCache.put(resId, drawable);
        }
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // 根据position获取对应的resId
        int resId = getResIdForPosition(position);
        Drawable drawable = drawableCache.get(resId);
        if (drawable != null) {
            holder.imageView.setImageDrawable(drawable);
        }
    }

    // ... 其他Adapter代码
}

这个方案的好处是没有额外依赖,逻辑直接,适合Drawable类型少的场景;缺点是如果Drawable数量太多,提前加载会占用内存。

方案3:换用Glide(原生支持VectorDrawable)

如果不想折腾Picasso的扩展,Glide从4.x版本开始原生支持VectorDrawable加载,而且自带完善的内存/磁盘缓存机制,复用性拉满。

示例代码:

Glide.with(context)
        .load(R.drawable.ic_vector)
        .into(holder.imageView);

Glide会自动处理VectorDrawable的复用,不用你操心缓存逻辑,而且对RecyclerView的优化做得很好,滑动流畅度有保障。如果项目可以切换图片加载库,这是最省心的方案。


最后提醒一下:不管用哪种方案,都要注意不要随意调用Drawable的mutate()方法(除非你需要修改某个实例的属性),因为mutate()会创建一个新的Drawable副本,破坏复用性。

内容的提问来源于stack exchange,提问作者f3ell0w

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:34:00