Universal Image Loader入门详解

Universal Image Loader for Android是一个图片加载库,实现了图片的异步加载、缓存和显示。
特性:

  • 多线程图片加载(同步、异步)
  • 丰富的设置选项
  • 缓存图片到内存中或SD/系统储存
  • 监听加载过程(包括下载过程)

UIL库文件下载地址
UIL官方演示APK
在本文中,我们将创建一个 demo ,它的主界面是一个 ListView ,调用 UIL 库,从网络上下载20张图片,插入到 ListView 中进行显示。

添加权限

需要添加两个权限:联网和读写SD卡。
修改文件:AndroidManifest.xml



布局

主布局直接设置一个ListView即可。
修改文件:res/layout/main.xml



列表项包含一个 ImageView 和 一个 TextView ,通过 LinearLayout 将其封装起来。
修改文件: res/layout/item_list_image.xml



    
    

adjustViewBounds 属性的作用是保持宽高比。
@string/descr_image 的值是 Image。
至此,布局的设计部分我们就完成了。至于 Java 部分的代码,我们放在后面,在设置好 UIL 之后再来实现。

设置UIL库

首先要对 UIL 进行设置。
创建全局对象 ImageLoader、DisplayImageOptions:

protected ImageLoader imageLoader;
private DisplayImageOptions options;

在 OnCreate里插入代码:
修改文件:src/com/judymax/uildemo/MainActivity.java

imageLoader = ImageLoader.getInstance();
imageLoader.init(ImageLoaderConfiguration.createDefault(this));
options = new DisplayImageOptions.Builder()
    .showImageOnLoading(R.drawable.ic_stub)
    .showImageForEmptyUri(R.drawable.ic_empty)
    .showImageOnFail(R.drable.ic_error)
    .cacheInMemory(true)
    .cacheOnDisk(true)
    .considerExifParams(true)
    .display(new RoundedBitmapDisplayer(20))
    .build();

ImageLoaderConfiguration.createDefault(this)是对Loader进行设置,我们采用默认设置。DisplayImageOptions是对显示方式进行设置,我们进行了一定的自定义:
showImageOnLoading指定了加载图片时显示的替代图片
showImageForEmptyUri制定了 Uri 为空时显示的替代图片
showImageOnFail 制定了加载失败时显示的替代图片
cacheInMemory和 cacheOnDisk 开启了两种缓存方式
RoundedBitmapDisplayer 圆角显示图片,弧度为20

ListView与ItemAdapter

上步中设置好了 UIL ,我们回到ListView上面来。
首先是引用我们设计的 ListView 布局,并给它设置一个 Adapter 。此处的 Adapter 是有我们自己定义的ItemAdapter。
修改文件:src/com/judymax/uildemo/MainActivity.java

ListView listView = (ListView) findViewById(android.R.id.list);
listView.setAdapter(new ItemAdapter());

关于 ItemAdapter 的实现,先给出代码,之后再进行说明:

private static class ViewHolder {
    TextView text;
    ImageView image;
}

private class ItemAdapter extends BaseAdapter {
    private SimpleImageLoadingListener imageLoadingListener = new SimpleImageLoadingListener();
    @Override
    public int getCount() {
        return imageUrls.length;
    }

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

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

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View view = convertView;
        final ViewHolder holder;
        if (convertView == null) {
            view = getLayoutInflater().inflate(R.layout.item_list_image, parent, false);
            holder = new ViewHolder();
            holder.text = (TextView) view.findViewById(R.id.text);
            holder.image = (ImageView) view.findViewById(R.id.image);
            view.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }
        holder.text.setText("图片" + (position + 1));
        imageLoader.displayImage(imageUrls[position], holder.image, options, imageLoadingListener);
        return view;
    }
}

SimpleImageLoadingListener是一个监听类,如果要获得当前图片的加载情况,可以通过重载其中的方法实现。
imageLoader.displayImage(imageUrls[position], holder.image, options, imageLoadingListener);实现了向image中插入图片。

图片URL数组

最后一步,需要创建一个全局的数组,用来保存待加载的图片的URL。
首先创建全局对象:

private String[] imageUrls;

在 OnCreate 中初始化:

imageUrls = new String[] {
    "http://image.haha.mx/2013/10/31/middle/1021863_eaa3e905a0f90d999e324a504ce5318e_1383154853.jpg",
    "http://image.haha.mx/2013/10/31/middle/1022418_0975752a4fa53613356df16f6f156a13_1383201220.jpg",
    "http://image.haha.mx/2013/10/27/middle/1018533_1219857b5efcc6887431a791bd31e121_1382879198.jpg",
    "http://image.haha.mx/2014/08/29/middle/1405464_3d6fbe203300b4528bf68ea11ca965b7_1409319483.jpg"
};

总结

程序的运行效果如下:
UILDemo
通过使用 UIL 库,可以实现高效加载图片,有效地避免 OOM 。本文作为入门抛砖引玉, UIL 库有着强大的功能和高度的可定制性,这些都留给我们在今后的工作中去实践、总结。
本 Demo 托管在 Github 上,共大家学习、交流。

附录:MainActivity.java

package com.judymax.uildemo;

import com.judymax.uildemo.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.BaseAdapter;
import android.widget.TextView;
import android.widget.ImageView;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;

public class MainActivity extends Activity
{
    protected ImageLoader imageLoader;
    private DisplayImageOptions options;
    private String[] imageUrls;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        imageUrls = new String[] {
            "http://image.haha.mx/2013/10/31/middle/1021863_eaa3e905a0f90d999e324a504ce5318e_1383154853.jpg",
            "http://image.haha.mx/2013/10/31/middle/1022418_0975752a4fa53613356df16f6f156a13_1383201220.jpg",
            "http://image.haha.mx/2013/10/27/middle/1018533_1219857b5efcc6887431a791bd31e121_1382879198.jpg",
            "http://image.haha.mx/2014/08/29/middle/1405464_3d6fbe203300b4528bf68ea11ca965b7_1409319483.jpg"
        };

        imageLoader = ImageLoader.getInstance();
        imageLoader.init(ImageLoaderConfiguration.createDefault(this));

        options = new DisplayImageOptions.Builder()
            .showImageOnLoading(R.drawable.ic_stub)
            .showImageForEmptyUri(R.drawable.ic_empty)
            .showImageOnFail(R.drawable.ic_error)
            .cacheInMemory(true)
            .cacheOnDisk(true)
            .considerExifParams(true)
            .displayer(new RoundedBitmapDisplayer(20))
            .build();
        
        ListView listView = (ListView) findViewById(android.R.id.list);
        listView.setAdapter(new ItemAdapter());
    }

    private static class ViewHolder {
        TextView text;
        ImageView image;
    }

    private class ItemAdapter extends BaseAdapter {
        private SimpleImageLoadingListener imageLoadingListener = new SimpleImageLoadingListener();
        @Override
        public int getCount() {
            return imageUrls.length;
        }

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

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

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            View view = convertView;
            final ViewHolder holder;
            if (convertView == null) {
                view = getLayoutInflater().inflate(R.layout.item_list_image, parent, false);
                holder = new ViewHolder();
                holder.text = (TextView) view.findViewById(R.id.text);
                holder.image = (ImageView) view.findViewById(R.id.image);
                view.setTag(holder);
            } else {
                holder = (ViewHolder) view.getTag();
            }
            holder.text.setText("图片" + (position + 1));
            imageLoader.displayImage(imageUrls[position], holder.image, options, imageLoadingListener);
            return view;
        }
    }
}