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

如何使用Volley在ListView中显示带标题描述的数据库图片?

用Volley实现ListView展示Base64图片、标题与描述的完整方案

嘿,我来帮你搞定这个需求!Volley本身就很适合处理这种网络请求+UI展示的场景,比你之前手动处理JSONObject更规范,还能帮你管理请求队列,下面是一步步的实现方法:

1. 先搞定基础准备

首先得确保你的项目配置正确:

  • 给Manifest加上网络权限:
<uses-permission android:name="android.permission.INTERNET" />
  • 在Gradle里添加Volley依赖(如果用AndroidX的话):
implementation 'com.android.volley:volley:1.2.1'

2. 创建数据模型类

之前你用HashMap存数据也能行,但用自定义模型类会让代码更清晰、易维护,比如定义一个Product类来封装每个条目的数据:

public class Product {
    private String title;
    private String description;
    private String imageBase64;

    public Product(String title, String description, String imageBase64) {
        this.title = title;
        this.description = description;
        this.imageBase64 = imageBase64;
    }

    // Getter方法,方便后续取数据
    public String getTitle() { return title; }
    public String getDescription() { return description; }
    public String getImageBase64() { return imageBase64; }
}

3. 用Volley发起网络请求获取数据

接下来用Volley的JsonObjectRequest去请求你的接口,解析返回的JSON数据成List<Product>,然后给ListView设置Adapter:

// 初始化Volley的请求队列,全局只需要初始化一次哦
RequestQueue requestQueue = Volley.newRequestQueue(this);
// 替换成你的实际接口地址
String apiUrl = "https://your-api-url.com/products";

JsonObjectRequest jsonRequest = new JsonObjectRequest(
        Request.Method.GET,
        apiUrl,
        null,
        response -> {
            List<Product> productList = new ArrayList<>();
            try {
                // 假设接口返回的JSON里,产品列表在"products"这个数组里,根据你的实际接口调整
                JSONArray productsArray = response.getJSONArray("products");
                for (int i = 0; i < productsArray.length(); i++) {
                    JSONObject unProduit = productsArray.getJSONObject(i);
                    // 取出标题、描述、Base64图片字符串
                    String title = unProduit.getString("title");
                    String description = unProduit.getString("description");
                    String imageBase64 = unProduit.getString("image");
                    // 添加到列表里
                    productList.add(new Product(title, description, imageBase64));
                }
                // 数据解析完成,初始化Adapter并设置给ListView
                ProductAdapter adapter = new ProductAdapter(YourActivity.this, productList);
                yourListView.setAdapter(adapter);
            } catch (JSONException e) {
                e.printStackTrace();
                Toast.makeText(YourActivity.this, "数据解析出错啦", Toast.LENGTH_SHORT).show();
            }
        },
        error -> {
            error.printStackTrace();
            Toast.makeText(YourActivity.this, "网络请求失败了", Toast.LENGTH_SHORT).show();
        }
);

// 把请求加入队列,Volley会自动处理
requestQueue.add(jsonRequest);

4. 自定义ListView的Adapter

创建ProductAdapter,用ViewHolder模式优化性能,同时处理Base64图片的解码和展示:

public class ProductAdapter extends BaseAdapter {
    private Context context;
    private List<Product> productList;
    private LayoutInflater inflater;
    // 可选:添加图片缓存,避免重复解码,提升性能
    private LruCache<String, Bitmap> imageCache;

    public ProductAdapter(Context context, List<Product> productList) {
        this.context = context;
        this.productList = productList;
        this.inflater = LayoutInflater.from(context);
        
        // 初始化图片缓存,用内存的1/8来存
        int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        int cacheSize = maxMemory / 8;
        imageCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getByteCount() / 1024;
            }
        };
    }

    @Override
    public int getCount() {
        return productList.size();
    }

    @Override
    public Object getItem(int position) {
        return productList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        // 复用convertView,避免重复创建视图
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.list_item_product, parent, false);
            holder = new ViewHolder();
            holder.productImage = convertView.findViewById(R.id.iv_product_image);
            holder.productTitle = convertView.findViewById(R.id.tv_product_title);
            holder.productDesc = convertView.findViewById(R.id.tv_product_desc);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        Product currentProduct = productList.get(position);
        // 设置标题和描述
        holder.productTitle.setText(currentProduct.getTitle());
        holder.productDesc.setText(currentProduct.getDescription());

        // 处理Base64图片:先从缓存取,没有再解码
        String base64Image = currentProduct.getImageBase64();
        Bitmap cachedBitmap = imageCache.get(base64Image);
        if (cachedBitmap != null) {
            holder.productImage.setImageBitmap(cachedBitmap);
        } else {
            try {
                byte[] decodedBytes = Base64.decode(base64Image, Base64.DEFAULT);
                Bitmap decodedBitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
                imageCache.put(base64Image, decodedBitmap);
                holder.productImage.setImageBitmap(decodedBitmap);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
                // 解码失败时设置默认图片
                holder.productImage.setImageResource(R.drawable.default_product_image);
            }
        }

        return convertView;
    }

    // ViewHolder类,缓存视图控件
    static class ViewHolder {
        ImageView productImage;
        TextView productTitle;
        TextView productDesc;
    }
}

5. 编写ListView的条目布局(list_item_product.xml)

最后写一个布局文件,定义每个列表条目的样式:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="16dp"
    android:gap="12dp">

    <ImageView
        android:id="@+id/iv_product_image"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:scaleType="centerCrop"
        android:background="@android:color/darker_gray" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical"
        android:gap="8dp">

        <TextView
            android:id="@+id/tv_product_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/tv_product_desc"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="14sp"
            android:textColor="@android:color/darker_gray" />
    </LinearLayout>
</LinearLayout>

额外小提示

  • 如果你的Base64图片很大,在主线程解码可能会卡顿,建议用异步任务(比如Coroutines或者AsyncTask)来解码图片,避免阻塞UI线程。
  • 记得在Activity销毁时,调用requestQueue.cancelAll(this)来取消未完成的请求,防止内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:58:31