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

使用Picasso批量缩放加载图片时性能卡顿的优化方案咨询

优化方案

一、核心问题分析

原代码性能差的原因主要有三点:

  • 每次加载图片都新建OkHttpClient和Picasso实例,每个实例都包含独立的线程池、缓存系统,重复创建会快速耗尽内存和CPU资源。
  • 用LinearLayout配合NestedScrollView加载大量图片时,所有ImageView会被一次性创建并加载,没有视图复用机制,内存占用急剧上升,导致卡顿。
  • 直接调用frameHolder.getWidth()可能在布局未完成时返回0,导致图片resize逻辑失效,加载原图进一步加重性能负担。

二、分步优化

1. 替换布局为RecyclerView

把NestedScrollView里的LinearLayout换成RecyclerView,利用其视图复用机制,只创建屏幕可见范围内的ImageView,大幅降低内存占用。

布局修改示例:

<!-- 替换原来的NestedScrollView+LinearLayout -->
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/image_recycler"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

编写RecyclerView的Adapter:

public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder> {
    private Context mContext;
    private List<ImageContent> mImages;
    private int mTargetWidth;
    private Picasso mPicasso;

    public ImageAdapter(Context context, List<ImageContent> images, int targetWidth, Picasso picasso) {
        mContext = context;
        mImages = images;
        mTargetWidth = targetWidth;
        mPicasso = picasso;
    }

    @NonNull
    @Override
    public ImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ImageView imageView = new ImageView(mContext);
        imageView.setLayoutParams(new RecyclerView.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        ));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        return new ImageViewHolder(imageView);
    }

    @Override
    public void onBindViewHolder(@NonNull ImageViewHolder holder, int position) {
        ImageContent img = mImages.get(position);
        // 动态添加请求头,复用全局Picasso实例
        mPicasso.load(img.getUrlContentData())
                .resize(mTargetWidth, 0)
                .onlyScaleDown() // 仅缩小图片,避免放大浪费资源
                .transform(new RequestTransformer() {
                    @Override
                    public Request transformRequest(Request request) {
                        return request.newBuilder()
                                .addHeader(img.getHeaderKey(), img.getHeaderValue())
                                .build();
                    }
                })
                .into(holder.imageView);
    }

    @Override
    public int getItemCount() {
        return mImages.size();
    }

    static class ImageViewHolder extends RecyclerView.ViewHolder {
        ImageView imageView;

        public ImageViewHolder(@NonNull ImageView itemView) {
            super(itemView);
            imageView = itemView;
        }
    }
}

2. 全局复用OkHttpClient和Picasso实例

只创建一次OkHttpClient和Picasso,避免重复初始化线程池、缓存等资源:

// 在Activity的onCreate方法中初始化全局实例
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

Picasso picasso = new Picasso.Builder(this)
        .downloader(new OkHttp3Downloader(okHttpClient))
        .build();

3. 正确获取目标宽度

确保获取到有效的适配宽度,避免resize失效:

// 获取屏幕宽度(适配全屏场景)
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
int targetWidth = displayMetrics.widthPixels;

// 若需匹配父布局宽度,可在布局完成后获取
frameHolder.post(() -> {
    int parentWidth = frameHolder.getWidth();
    // 初始化Adapter时传入parentWidth
});

4. 可选:改用Glide加载图片

Glide在内存缓存、自动内存管理上表现更优,适合大量图片场景,实现示例:

// 在Adapter的onBindViewHolder中替换为Glide加载
Glide.with(mContext)
        .load(img.getUrlContentData())
        .addHeader(img.getHeaderKey(), img.getHeaderValue())
        .override(mTargetWidth, Target.SIZE_ORIGINAL)
        .fitCenter()
        .into(holder.imageView);

三、最终整合代码示例

public class YourActivity extends AppCompatActivity {
    private RecyclerView mImageRecycler;
    private Picasso mPicasso;
    private int mTargetWidth;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.your_activity_layout);

        // 获取适配宽度
        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        mTargetWidth = displayMetrics.widthPixels;

        // 初始化全局图片加载实例
        OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
        mPicasso = new Picasso.Builder(this)
                .downloader(new OkHttp3Downloader(okHttpClient))
                .build();

        // 初始化RecyclerView
        mImageRecycler = findViewById(R.id.image_recycler);
        mImageRecycler.setLayoutManager(new LinearLayoutManager(this));
    }

    public void displayImages(List<ImageContent> images) {
        ImageAdapter adapter = new ImageAdapter(this, images, mTargetWidth, mPicasso);
        mImageRecycler.setAdapter(adapter);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 04:25:19