背景:
Android中图片处理存在的难点:
1.OOM内存溢出;
2.图片尺寸和缩略图处理的平衡;
3.网络图片的加载与缓存机制;
简介:
Universal-ImageLoader是目前Android主流的图片处理库框架之一,作者是白俄罗斯的Sergey Tarasevich。
在Android图片处理中需要考虑的问题很多,例如OOM、图片缓存和网络图片加载、多线程问题及图片压缩处理等等复杂的问题。但是Universal-ImageLoader已经帮我们把这些问题处理好了,对外提供了相应的完善的请求API,我们只需要按照要求使用即可。
特点:
1.支持本地图片和网络图片的多线程异步加载和缓存处理;
2.个性化的配置自己项目的ImageLoader;
3.图片加载过程的监听回调;
4.自动对加载的图片针对当前剩余内存进行裁剪优化,防止OOM;
5.较好的控制图片的加载过程,例如暂停图片加载,重新开始加载图片;
缺点:
没有对本地文件压缩处理的相关API方法以及默认都是Src模式设置图片,没有针对Background属性开放API。
用法:
1.Universal-ImageLoader的配置:
可以全局配置:在Application里进行配置。
可以针对单一加载图片的地方配置。
例如:可配置图片缓存保存路径、线程池内加载的数量、缓存的文件数量 、每个缓存文件的最大长宽、加载过程中和加载失败时显示的图片等等。
2.用Universal-ImageLoader加载网络图片和本地图片:
Universal-ImageLoader支持网络图片的加载和本地图片的加载,而且可以自动缓存、自动根据当前手机环境进行压缩处理防止出现OOM。
也可以监听整个图片的加载过程,可控。
下面实现一个ListView显示网络图片:
首先需要在工程中加入Universal-ImageLoader的jar包,然后在Manifest中加入读取sd卡的权限和访问网络的权限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
然后在MyApplication中配置Universal-ImageLoader
import java.io.File; import android.app.Application; import android.graphics.Bitmap; import android.os.Environment; import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator; import com.nostra13.universalimageloader.cache.memory.impl.UsingFreqLimitedMemoryCache; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import com.nostra13.universalimageloader.core.assist.ImageScaleType; import com.nostra13.universalimageloader.core.assist.QueueProcessingType; import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer; import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer; import com.nostra13.universalimageloader.core.download.BaseImageDownloader; public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder( MyApplication.this) // max width, max height,即保存的每个缓存文件的最大宽高 .memoryCacheExtraOptions(100, 100) // 线程池内加载的数量 .threadPoolSize(3) .threadPriority(Thread.NORM_PRIORITY - 1) .memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)) .memoryCacheSize(2 * 1024 * 1024) .diskCacheSize(50 * 1024 * 1024) // 将保存的时候的URI名称用MD5 加密 .diskCacheFileNameGenerator(new Md5FileNameGenerator()) .diskCacheFileCount(100) // 自定义缓存路径 .diskCache( new UnlimitedDiscCache(new File(Environment .getExternalStorageDirectory() + ""))) .denyCacheImageMultipleSizesInMemory() .tasksProcessingOrder(QueueProcessingType.FIFO) .defaultDisplayImageOptions(getDisplayOptions()) .imageDownloader(new BaseImageDownloader(this, 5*1000, 30*1000)) //.writeDebugLogs() .build(); //开始构建 ImageLoader.getInstance().init(config); } private DisplayImageOptions getDisplayOptions() { DisplayImageOptions options; options = new DisplayImageOptions.Builder() .showImageOnLoading(R.drawable.ic_launcher) // 设置图片在下载期间显示的图片 .showImageForEmptyUri(R.drawable.ic_launcher)// 设置图片Uri为空或是错误的时候显示的图片 .showImageOnFail(R.drawable.ic_launcher) // 设置图片加载/解码过程中错误时候显示的图片 .cacheInMemory(true)// 设置下载的图片是否缓存在内存中 .cacheOnDisc(true)// 设置下载的图片是否缓存在SD卡中 .considerExifParams(true) // 是否考虑JPEG图像EXIF参数(旋转,翻转) .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)// 设置图片以如何的编码方式显示 .bitmapConfig(Bitmap.Config.RGB_565)// 设置图片的解码类型// // .delayBeforeLoading(int delayInMillis)//int // delayInMillis为你设置的下载前的延迟时间 // 设置图片加入缓存前,对bitmap进行设置 // .preProcessor(BitmapProcessor preProcessor) .resetViewBeforeLoading(true)// 设置图片在下载前是否重置,复位 .displayer(new RoundedBitmapDisplayer(20))// 是否设置为圆角,弧度为多少 .displayer(new FadeInBitmapDisplayer(100))// 是否图片加载好后渐入的动画时间 .build();// 构建完成 return options; } }
这里找了四张网络菜谱图片,在代码中新添加一个菜类:
//表示菜类(经过烹调的蔬菜、蛋品、肉类等) public class Dish { private String imgUrl; // 图片地址 private String name; // 菜名 private String price; // 菜价 public Dish(String imgUrl, String name, String price) { this.imgUrl = imgUrl; this.name = name; this.price = price; } public String getImgUrl() { return imgUrl; } public void setImgUrl(String imgUrl) { this.imgUrl = imgUrl; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } }
主界面类中,首先获取到ImageLoad对象,然后调用该对象的displayImage方法加载网络图片
import java.util.ArrayList; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; import android.app.Activity; import android.graphics.Bitmap; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends Activity { /** * 如果需要读取本地图片,可以使用 * String uri = "file:///" + "本地路径"; */ private ImageLoader mImageLoader; private static final String BASE_URL = "http://img1.3lian.com/img2011/w1/106/85/"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //获取到ImageLoader对象 mImageLoader = ImageLoader.getInstance(); ArrayList<Dish> dishList = new ArrayList<Dish>(); dishList.add(new Dish(BASE_URL+"42.jpg", "水煮鱼片", "38.00")); dishList.add(new Dish(BASE_URL+"34.jpg", "小炒肉", "18.00")); dishList.add(new Dish(BASE_URL+"37.jpg", "清炒时蔬", "15.00")); dishList.add(new Dish(BASE_URL+"11.jpg", "金牌烤鸭", "36.00")); dishList.add(new Dish(BASE_URL+"12.jpg", "粉丝肉煲", "20.00")); ListView mListView = (ListView) this.findViewById(R.id.listview); MainListViewAdapter adapter = new MainListViewAdapter(dishList); mListView.setAdapter(adapter); } //网络图片加载监听器对象 private ImageLoadingListener mImageLoadingListener = new ImageLoadingListener() { @Override public void onLoadingStarted(String arg0, View arg1) { System.out.println("onLoadingStarted..."); } @Override public void onLoadingFailed(String arg0, View arg1, FailReason arg2) { System.out.println("onLoadingFailed..."); } @Override public void onLoadingComplete(String arg0, View arg1, Bitmap arg2) { System.out.println("onLoadingComplete..."); } @Override public void onLoadingCancelled(String arg0, View arg1) { System.out.println("onLoadingCancelled..."); } }; //ListView适配器 private class MainListViewAdapter extends BaseAdapter { private ArrayList<Dish> dishList; public MainListViewAdapter(ArrayList<Dish> list) { this.dishList = list; } @Override public int getCount() { return dishList.size(); } @Override public Object getItem(int position) { return dishList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ListViewItemHolder item = null; if (convertView == null) { convertView = LayoutInflater.from(MainActivity.this).inflate( R.layout.main_listview_item, null); item = new ListViewItemHolder(); item.img_iv = (ImageView) convertView .findViewById(R.id.imageView1); item.name_textview = (TextView) convertView .findViewById(R.id.textView1); item.price_textview = (TextView) convertView .findViewById(R.id.textView2); convertView.setTag(item); } else { item = (ListViewItemHolder) convertView.getTag(); } Dish dish = dishList.get(position); //这里就是加载网络图片,加载的整个过程都会有调用监听器中的回调方法 mImageLoader.displayImage(dish.getImgUrl(), item.img_iv, mImageLoadingListener); item.name_textview.setText(dish.getName()); item.price_textview.setText(dish.getPrice()+"元"); return convertView; } } //ListView的Item组件类 private class ListViewItemHolder { ImageView img_iv; TextView name_textview; TextView price_textview; } }
下面是整个工程的下载链接,有兴趣的可以下载导入到自己的Eclipse中去运行: