Universal_image_loader加载网络图片

本文详细介绍如何使用Universal Image Loader加载大量网络图片至ListView,并探讨内存缓存与SD卡缓存策略,线程池管理,以及ImageLoader核心配置。

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

对于从网络上加载大量的图片到Listview中在应用中是特别常见的,但是对于内存缓存来说,无论做的再好,当应用程序销毁时,图片也就销毁。因此把listview中从网络中获取的图片保存到本地,一方面使应用变得流畅,另一方面节省流量。对于这样的需求Universal_image_loader天生做这样的工作。

这里写图片描述


可能用到的相关知识:

1、内存缓存与sd卡缓存
  1. 内存缓存:把从网络加载的图片缓存到内存中,当再次请求时,先从内存中获取,如果内存中没有,则从网络获取。
  2. sd卡缓存:加载图片时,先从sd卡中获取,如果sd卡中没有,则查找内存缓存,如果也没有,从网络获取
2、线程,线程池的相关知识
  1. 线程的生命周期包括创建,就绪,运行,阻塞,销毁阶段。如果我们处理的任务数目较少,可以自己创建多个线程来处理相应的任务。但是如果处理的任务数目相当多,由于创建线程,销毁线程本身就有大量的工作,因此当任务数量比较多时,就可以采用线程池。
  2. 当采用线程池的时候,我们可以规定线程池,线程的数量,当一个线程执行完一个任务的时候,会接着执行另一个任务,如果这个线程发生异常,则由另一个线程池中的线程来代替。
  3. 如果任务数量多于线程数量,则没有完成的任务处于等待阶段。
  4. 线程池的组成部分:
    1、线程池管理器(ThreadPoolManager):用于创建并管理线程池
    2、工作线程(WorkThread): 线程池中线程
    3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。
    4、任务队列:用于存放没有处理的任务。提供一种缓冲机制。
3、线程的优先级
  1. 线程的优先级,是指线程的先后执行顺序。在java中通过.setPriority(); 来设置线程的级别。
  2. Java线程的优先级是一个整数,其取值范围是1 - 10 ,数值越大,优先级别越高。
  3. Thread源代码里对NORM_PRIORITY (数值为5) 的注释是“线程默认的优先级“。
4、image_loader使用中常用的类分析

ImageLoaderConfiguration做的是一些全局配置,主要有线程类、缓存大小、磁盘大小、图片下载与解析、日志方面的配置。

ImageLoader是具体下载图片,缓存图片,显示图片的具体执行类。

DisplayImageOptions用于显示每一个的Imageloader根据网络图片的状态(空白、下载错误、正在下载)显示对应的图片,是否将缓存加载到磁盘上,下载完后对图片进行怎么样的处理。


使用universal-image-loader加载图片代码如下:
在Application中做的全局初始化工作:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        initImageLoader(getApplicationContext());
    }
    private void initImageLoader(Context context) {
        // TODO Auto-generated method stub
        //缓存文件名称:当删除应用时,缓存文件也删除;
        File cacheDir=StorageUtils.getCacheDirectory(getApplicationContext());
        //初始化imageloaderConfiguration配置;
        ImageLoaderConfiguration config=new ImageLoaderConfiguration.Builder(context)
        //设置线程优先级;默认级别是5,在这里可以设置一个,3或者4级别都行。
        .threadPriority(Thread.NORM_PRIORITY-1)
        .denyCacheImageMultipleSizesInMemory()
        .discCacheFileNameGenerator(new Md5FileNameGenerator())
        .tasksProcessingOrder(QueueProcessingType.LIFO)
        .discCache(new UnlimitedDiscCache(cacheDir))
        //设置在缓存sd卡上为5M,当大于5M用LRU算法清理
        .discCacheSize(5*1024*1024)
        .discCacheFileNameGenerator(new HashCodeFileNameGenerator())
        .discCacheFileCount(100)
        .writeDebugLogs()
        .build();
        ImageLoader.getInstance().init(config);
    }
}

在ImageLoaderConfiguration中的常用设置:

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
        .taskExecutor(...)//添加个线程池,进行下载
        .taskExecutorForCachedImages(...)//添加线程池缓存图片;
        .threadPoolSize(4) // 线程池线程数量设置;
        .threadPriority(Thread.NORM_PRIORITY - 1) // 设置线程的优先级
        .tasksProcessingOrder(QueueProcessingType.FIFO) //设置图片下载和显示的工作队列排序
        .denyCacheImageMultipleSizesInMemory()//当同一个Uri获取不同大小的图片,缓存到内存时,只缓存一个。默认会缓存多个不同的大小的相同图片
        .memoryCache(new LruMemoryCache(2 * 1024 * 1024))//设置内存缓存,使用lru算法管理;
        .memoryCacheSize(2 * 1024 * 1024)//设置内存缓存的大小;
        .memoryCacheSizePercentage(13) //设置内存缓存
        .diskCache(new UnlimitedDiscCache(cacheDir)) //缓存没有限制;
        .diskCacheSize(50 * 1024 * 1024)//设置缓存的大小
        .diskCacheFileCount(100)//设置缓存文件的数量
        .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) //通过HashCode将url生成文件名

Madapter中的代码如下:

public class MyAdapter extends BaseAdapter {
    private Context context;
    private String[] images;
    private ImageLoader imageLoader;
    DisplayImageOptions options;
    //对imageloading设置监听事件;
    private ImageLoadingListener animateFirstListener = new AnimateFirstDisplayListener();
    public MyAdapter(Context context, String[] images) {
        this.context = context;
        this.images = images;
        imageLoader = ImageLoader.getInstance();
        options = new DisplayImageOptions.Builder()
                .showImageOnLoading(R.drawable.ic_stub)
                .showImageForEmptyUri(R.drawable.ic_empty)
                .showImageOnFail(R.drawable.ic_error)
                .cacheInMemory(true)
                .cacheOnDisc(true)
                .considerExifParams(true)
                .displayer(new RoundedBitmapDisplayer(15))
                .build();
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return images.length;
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) {
        // TODO Auto-generated method stub
        ViewHolder vh;
        if (convertView == null) {
            vh = new ViewHolder();
            convertView = LayoutInflater.from(context).inflate(R.layout.item,
                    null);
            vh.imageview = (ImageView) convertView.findViewById(R.id.imageview);
            vh.textview = (TextView) convertView.findViewById(R.id.textview);
            convertView.setTag(vh);
        } else {
            vh = (ViewHolder) convertView.getTag();
        }
        vh.textview.setText("item"+position);
        imageLoader.displayImage(images[position], vh.imageview, options,
                animateFirstListener);
        return convertView;
    }

    static final class ViewHolder {
        ImageView imageview;
        TextView textview;
    }
    private static class AnimateFirstDisplayListener extends SimpleImageLoadingListener {

        static final List<String> displayedImages = Collections.synchronizedList(new LinkedList<String>());

        @Override
        public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
            if (loadedImage != null) {
                ImageView imageView = (ImageView) view;
                boolean firstDisplay = !displayedImages.contains(imageUri);
                if (firstDisplay) {
                    FadeInBitmapDisplayer.animate(imageView, 500);
                    displayedImages.add(imageUri);
                }
            }
        }
    }

DisplayImageOptions 中的常用设置:

DisplayImageOptionsoptions = new DisplayImageOptions.Builder()
        .showImageOnLoading(R.drawable.ic_launcher)//下载时间显示的图片  
        .showImageForEmptyUri(R.drawable.ic_launcher)//设置图片Uri为空或是错误的时候显示的图片  
        .showImageOnFail(R.drawable.ic_launcher)//错误时候显示的图片
        .cacheInMemory(true)//缓存到内存中
        .cacheOnDisk(true)//缓存到sd卡中;
        .displayer(new FadeInBitmapDisplayer(100))
        .considerExifParams(true)
        .displayer(new FadeInBitmapDisplayer(100))// 图片加载好后渐入的动画时间
        .displayer(new RoundedBitmapDisplayer(1)).build();//设置图片的圆角显示;值越大,圆角的弧度就越大

Activity中的代码如下:

public class MainActivity extends ActionBarActivity {
    private ListView listview;
    private MyAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listview=(ListView) findViewById(R.id.listview);
        adapter=new MyAdapter(this,Constants.images);
        listview.setAdapter(adapter);    
    }
}

注意:1导jar包。
2.加权限。
3.在application节点中配置名称。

图片在sd卡上的缓存路径:sdcard/Android/data/包名/cache
运行app后,退出应用,关闭网络,再次进入,图片依然可以显示出来

Demo下载地址eclipse版
http://download.youkuaiyun.com/detail/androidxiaogang/9199847

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值