ListView显示图片(Volley+ImageRequest+LruCache+DiskCache)

本文介绍如何使用Volley库结合LruCache和DiskCache实现Android应用中的图片加载及缓存策略,包括内存和硬盘缓存的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<首先需要下载volley.jar的开发包,并导入项目中: volley.jar>

      使用Volley+ImageRequest下载图片,并使用LruCache进行内存缓存,同时使用DiskCache进行硬盘缓存:

首先是ImageCache的接口:

package mxd.com.wxproject.imgList;

import android.graphics.Bitmap;

/**
 * Created on 16/6/12.
 */
public interface ImageCache
{
    public Bitmap get(String url);

    public void put(String url, Bitmap bitmap);

}


      MemoryCache用来进行内存缓存:

package mxd.com.wxproject.imgList;

import android.graphics.Bitmap;
import android.util.LruCache;

/**
 * Created on 16/6/12.
 */
public class MemoryCache implements ImageCache
{

    private static LruCache<String, Bitmap> mCache = null;

    private static final String cacheTag = "ImageCache";

    public MemoryCache()
    {
        mCache = initMemoryCache();
    }

    public LruCache<String, Bitmap> initMemoryCache()
    {
        if (mCache == null)
        {
            synchronized (cacheTag)
            {
                if (mCache == null)
                {
                    int maxMemory = (int) Runtime.getRuntime().maxMemory() / 1024;
                    int cacheMemory = maxMemory / 4;
                    mCache = new LruCache<String, Bitmap>(cacheMemory)
                    {
                        @Override
                        protected int sizeOf(String key, Bitmap bitmap)
                        {
                            // 每次存储,删除时调用
                            return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
                        }
                    };
                }
            }
        }
        return mCache;
    }

    @Override
    public Bitmap get(String url)
    {
        return mCache.get(url);
    }

    @Override
    public void put(String url, Bitmap bitmap)
    {
        mCache.put(url, bitmap);
    }
}


      DiskCache用来进行硬盘缓存:

package mxd.com.wxproject.imgList;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created on 16/6/12.
 */
public class DiskCache implements ImageCache
{

    private static final String cacheDir = "sdcard/cache/";

    @Override
    public Bitmap get(String url)
    {
        return BitmapFactory.decodeFile(cacheDir + url);
    }

    @Override
    public void put(String url, Bitmap bitmap)
    {
        FileOutputStream fileOutputStream = null;

        try
        {
            fileOutputStream = new FileOutputStream(cacheDir + url);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
        } catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }finally
        {
            if (fileOutputStream != null)
            {
                try
                {
                    fileOutputStream.close();
                } catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
}


      DoubleCache用来进行双重缓存,每次拿到Bitmap的url时,首先从内存缓存(MemoryCache-LruCache)中获取Bitmap,如果获取得到则setImageBitmap到ImageView,否则则从DiskCache中获取Bitmap,如果获取得到,则setImageBitmap到ImageView上,同时缓存到内存中,否则使用Volley+ImageRequest进行网络下载:

package mxd.com.wxproject.imgList;

import android.graphics.Bitmap;

/**
 * Created on 16/6/12
 */
public class DoubleCache implements ImageCache
{

    ImageCache memoryCache = null;
    ImageCache diskCache = null;

    public DoubleCache()
    {
        memoryCache = new MemoryCache();
        diskCache = new DiskCache();
    }

    @Override
    public Bitmap get(String url)
    {
        Bitmap bmp = memoryCache.get(url);
        if (bmp == null)
        {
            bmp = diskCache.get(url);
            if (bmp != null)
            {
                memoryCache.put(url, bmp);
            }
        }
        return bmp;
    }

    @Override
    public void put(String url, Bitmap bitmap)
    {
        memoryCache.put(url, bitmap);
        diskCache.put(url, bitmap);
    }
}


      下面是用来执行ImageRequest进行网络请求的RequestQueue的单例:

package mxd.com.wxproject.imgList;

import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageRequest;
import com.android.volley.toolbox.Volley;

import mxd.com.wxproject.WXApp;

/**
 * Created on 16/6/12.
 */
public class HttpQueue
{

    public HttpQueue()
    {
        queues = getHttpQueue();
    }

    private static final String queueTag = "HttpQueue";
    private static RequestQueue queues = null;

    private RequestQueue getHttpQueue()
    {
        if (queues == null)
        {
            synchronized (queueTag)
            {
                if (queues == null)
                {
                    queues = Volley.newRequestQueue(WXApp.getAppContext());
                }
            }
        }
        return queues;
    }

    public void addImageRequest(ImageRequest request)
    {
        queues.add(request);
    }

}

      下面是用来获取图片的ImageLoaderUtils工具:

package mxd.com.wxproject.imgList;

import android.graphics.Bitmap;
import android.util.LruCache;
import android.widget.ImageView;

import com.android.volley.Response;
import com.android.volley.toolbox.ImageRequest;

import mxd.com.wxproject.WXApp;

/**
 * Created on 16/6/8.
 */
public class ImageLoaderUtils
{

    private HttpQueue queues = null;
    private DoubleCache imageCache = null;

    public ImageLoaderUtils()
    {
        this.imageCache = new DoubleCache();
        this.queues = new HttpQueue();
    }

    public void showImageByVolley(ImageView imageView, String url)
    {
        if (imageCache.get(url) == null)
        {
            getBitmapByRequest(imageView, url);
        } else
        {
            imageView.setImageBitmap(this.imageCache.get(url));
        }
    }

    private void getBitmapByRequest(final ImageView imageView, final String url)
    {
        ImageRequest request = new ImageRequest(url, new Response.Listener<Bitmap>()
        {
            @Override
            public void onResponse(Bitmap bitmap)
            {
                if (imageView.getTag().equals(url))
                {
                    imageView.setImageBitmap(bitmap);
                }
                imageCache.put(url, bitmap);
            }
        }, 0, 0, Bitmap.Config.RGB_565, null);

        queues.addImageRequest(request);
    }

}

      下面是ListView的适配器Adapter:

package mxd.com.wxproject.imgList;

import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.android.volley.Response;
import com.android.volley.toolbox.ImageRequest;

import java.util.List;

import mxd.com.wxproject.R;
import mxd.com.wxproject.WXApp;

/**
 * Created on 16/6/7.
 */
public class ImgAdapter extends BaseAdapter
{

    LayoutInflater inflater;
    List<ImgItem> datas;

    ImageLoaderUtils loaderUtils;

    public ImgAdapter(Context context, List<ImgItem> datas)
    {
        this.inflater = LayoutInflater.from(context);
        this.datas = datas;

        loaderUtils = new ImageLoaderUtils();
    }

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

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        ViewHolder viewHolder = null;
        if (convertView == null)
        {
            convertView = inflater.inflate(R.layout.listview_img, null);
            viewHolder = new ViewHolder();

            viewHolder.tv_listView_imgName = (TextView) convertView.findViewById(R.id.tv_listView_imgName);
            viewHolder.tv_listView_imgNum = (TextView) convertView.findViewById(R.id.tv_listView_imgNum);
            viewHolder.img_listView_icon = (ImageView) convertView.findViewById(R.id.img_listView_icon);

            convertView.setTag(viewHolder);
        } else
        {
            viewHolder = (ViewHolder) convertView.getTag();
            viewHolder.img_listView_icon.setImageBitmap(null);
        }

        ImgItem item = datas.get(position);
        viewHolder.tv_listView_imgName.setText(item.imgName);
        viewHolder.tv_listView_imgNum.setText(item.imgNum);

        String imgUrl = item.imgUrl;
        viewHolder.img_listView_icon.setTag(imgUrl);
        loaderUtils.showImageByVolley(viewHolder.img_listView_icon, imgUrl);

        return convertView;
    }

    private class ViewHolder
    {
        ImageView img_listView_icon;
        TextView tv_listView_imgName;
        TextView tv_listView_imgNum;
    }
}

      除上面的代码以外,在HttpQueue.java中,调用Volley的newRequestQueue()方法,对RequestQueue进行实例化时,需要一个Context上下文对象,我们使用Application的上下文对象,保证RequestQueue在整个APP生命周期的有效性:

package mxd.com.wxproject;

import android.app.Application;
import android.content.Context;

/**
 * Created on 16/6/7.
 */
public class WXApp extends Application
{
    private static Context context;

    @Override
    public void onCreate()
    {
        super.onCreate();

        context = getApplicationContext();
    }

    public static Context getAppContext()
    {
        return context;
    }

}

      配置AndroidManifest文件,为Application添加name属性:

<application
    android:name=".WXApp"

      并添加网络权限,SDcard读写权限:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>


      下面附加ImgItem对象文件(ImgItem.java):

package mxd.com.wxproject.imgList;

/**
 * Created on 16/6/7.
 */
public class ImgItem
{

    public String imgUrl;
    public String imgName = "";
    public String imgNum = "-1";

}

      有了上面的代码,就可以通过Thread和Runnable实现请求List<ImgItem>的操作,获得成功List<ImgItem>之后,就可以异步显示ListView内容了:

ImgAdapter adapter = new ImgAdapter(getContext(), datas);
listView.setAdapter(adapter);

效果如下:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值