Android中使用ImageLoader加载图片
2016-09-12 18:04
411 查看
Android上让人头疼的莫过于从网络上获取图片,然后显示图片,最后还要考虑到图片的回收问题,这之间只要有任何一个环节有问题都可能直接OOM。尤其在需要展示图片的列表页面,会加载大量网络上的图片,每当快速滑动列表的时候,都会很卡,甚至会因为内存溢出而崩溃。
这时就是ImageLoader的 show time
了。ImageLoader的目的是为了实现异步的网络图片加载、缓存及显示,支持多线程异步加载。
ImageLoader在GitHub的下载地址:https://github.com/nostra13/Android-Universal-Image-Loader。
ImageLoader的工作原理是这样的:在显示图片的时候,它会先在内存中查找;如果没有,就去本地查找;如果还没有,就开一个新的线程去下载这张图片,下载成功会把图片同时缓存到内存和本地。
基于这个原理,我们可以在每一次退出一个页面的时候,把ImageLoader内存中的缓存全都清除,这样就节省了大量内存,反正下次再用到的时候从本地再取出来就是了。
此外,由于ImageLoader对图片是软引用的形式,所以内存中的图片会在内存不足的时候被系统回收(内存足够的时候不会对其进行垃圾回收)。
上面说到了ImageLoader的设计原理,下面来说ImageLoader的使用。
ImageLoader的三大组件:
ImageLoaderConfiguration——对图片缓存进行总体配置,包挎内存缓存的大小、本地缓存的大小和位置、日志、下载策略(FIFO还是LIFO)等等。
ImageLoader——我们一般使用displayImage来把URL对应的图片显示在ImageView上。
ImageLoaderOptions——在每个页面需要显示图片的地方,控制如何显示的细节,比如指定下载时的默认图(包括下载中、下载失败、URL为空等),是否将缓存放到内存或者本地磁盘。
在这里,从我正在研读的一本书上借用一段话描述以上三者的关系。书中的这段话也是引用了博客园上陈哈哈的博文。原文如下:
===========================================
他们有点像厨房规定、厨师、客户个人口味之间的关系。ImageLoaderConfiguration就像是厨房里面的规定,每一个厨师要怎么着装,要怎么保持厨房的干净,这是针对每一个厨师都适用的规定,而且不允许个性化改变。ImageLoader就像是具体做菜的厨师,负责具体菜谱的制作。DisplayImageOptions就像是每个客户的偏好,根据客户是重口味还是清淡,每一个ImageLoader根据DisplayImageOptions的要求具体执行。
下面就开始给大家讲讲怎么使用ImageLoader:
1、重写application,并初始化配置
在使用ImageLoader的实例之前,你需要初始化该配置,否则会报初始化错误。一般我们直接写在application中初始化。
在初始化配置完成后,在清单配置文件中写入你自定义的application,并写入访问权限。如下图所示:
到这里基本的配置就完了,接下来就是加载图片了。
2、在使用ImageView加载图片的地方,配置当前页面的ImageLoader选项。有可能是Activity,也有可能是Adapter。我这个demo是在adapter里面配置DisplayImageOptions对象。代码如下所示:
上面的代码中我都给出了注释,方便大家理解。这里我给出的是网络上的图片的URL和drawable下的图片的URL,比如上面的ImageLoaderBaseAdapter 里,使用ImageLoader对象加载图片的方法如下:
其中displayImage方法的第一个参数是图片的URL,第二个参数是ImageView控件。
一般来说,ImageLoader性能如果有问题,就和这里的配置有关,尤其是ImageLoaderConfiguration。而这里上面的一些配置代码都是目前比较通用的,大家可以参考。
最后给大家讲讲ImageLoader的优化吧!这是我现在正在研读的一本书上面提到的,这里分享给大家。原文如下:
===========================================
尽管ImageLoader很强大,但一直把图片缓存在内存中,会导致内存占用过高。虽然对图片的引用是软引用,软引用在内存不够的时候会被GC,但我们还是希望减少GC的次数,所以要经常手动清理ImageLoader中的缓存。
我们在上面MainActivity的 onDestroy()生命周期方法中,执行了ImageLoader的clearMemoryCache方法,以确保页面销毁时,把为了显示这个页面而增加的内存缓存清除。这样,即使到了下个页面要复用之前加载过的图片,虽然内存中没有了,根据ImageLoader的缓存策略,还是可以在本地磁盘上找到:
这里加载图片时候,写图片的URL的时候需要注意,图片的URL可以分为以下几种:
好了,所有的配置和方法都讲完了。下面给大家演示一下加载的图片效果:
listView的第一张图片
listView的第二张图片
listView的第三张图片
listView的最后一张图片,最后的小狗图片是drawable下的图片资源
这里我写的demo只加载了网络的和drawable下的图片,其他的图片加载大家就自己去试试看,其实就是URL的写法,这里就不过多讲了,上面有讲到。最后大家别忘了给清单配置文件加网络权限和写权限:
ImageLoader的jar包资源:点我下载
加载图片的Demo:点我下载
这时就是ImageLoader的 show time
了。ImageLoader的目的是为了实现异步的网络图片加载、缓存及显示,支持多线程异步加载。
ImageLoader在GitHub的下载地址:https://github.com/nostra13/Android-Universal-Image-Loader。
ImageLoader的工作原理是这样的:在显示图片的时候,它会先在内存中查找;如果没有,就去本地查找;如果还没有,就开一个新的线程去下载这张图片,下载成功会把图片同时缓存到内存和本地。
基于这个原理,我们可以在每一次退出一个页面的时候,把ImageLoader内存中的缓存全都清除,这样就节省了大量内存,反正下次再用到的时候从本地再取出来就是了。
此外,由于ImageLoader对图片是软引用的形式,所以内存中的图片会在内存不足的时候被系统回收(内存足够的时候不会对其进行垃圾回收)。
上面说到了ImageLoader的设计原理,下面来说ImageLoader的使用。
ImageLoader的三大组件:
ImageLoaderConfiguration——对图片缓存进行总体配置,包挎内存缓存的大小、本地缓存的大小和位置、日志、下载策略(FIFO还是LIFO)等等。
ImageLoader——我们一般使用displayImage来把URL对应的图片显示在ImageView上。
ImageLoaderOptions——在每个页面需要显示图片的地方,控制如何显示的细节,比如指定下载时的默认图(包括下载中、下载失败、URL为空等),是否将缓存放到内存或者本地磁盘。
在这里,从我正在研读的一本书上借用一段话描述以上三者的关系。书中的这段话也是引用了博客园上陈哈哈的博文。原文如下:
===========================================
他们有点像厨房规定、厨师、客户个人口味之间的关系。ImageLoaderConfiguration就像是厨房里面的规定,每一个厨师要怎么着装,要怎么保持厨房的干净,这是针对每一个厨师都适用的规定,而且不允许个性化改变。ImageLoader就像是具体做菜的厨师,负责具体菜谱的制作。DisplayImageOptions就像是每个客户的偏好,根据客户是重口味还是清淡,每一个ImageLoader根据DisplayImageOptions的要求具体执行。
下面就开始给大家讲讲怎么使用ImageLoader:
1、重写application,并初始化配置
public class AppContext extends Application { /** * Called when the application is starting, before any activity, service, or * receiver objects (excluding content providers) have been created. * (当应用启动的时候,会在任何activity、Service或者接收器被创建之前调用,所以在这里进行ImageLoader 的配置) * 当前类需要在清单配置文件里面的application下进行name属性的设置。 */ @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); // 缓存图片的配置,一般通用的配置 initImageLoader(getApplicationContext()); } private void initImageLoader(Context context) { // TODO Auto-generated method stub // 创建DisplayImageOptions对象 DisplayImageOptions defaulOptions = new DisplayImageOptions.Builder() .cacheInMemory(true).cacheOnDisk(true).build(); // 创建ImageLoaderConfiguration对象 ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder( context).defaultDisplayImageOptions(defaulOptions) .threadPriority(Thread.NORM_PRIORITY - 2) .denyCacheImageMultipleSizesInMemory() .diskCacheFileNameGenerator(new Md5FileNameGenerator()) .tasksProcessingOrder(QueueProcessingType.LIFO).build(); // ImageLoader对象的配置 ImageLoader.getInstance().init(configuration); } }
在使用ImageLoader的实例之前,你需要初始化该配置,否则会报初始化错误。一般我们直接写在application中初始化。
在初始化配置完成后,在清单配置文件中写入你自定义的application,并写入访问权限。如下图所示:
到这里基本的配置就完了,接下来就是加载图片了。
2、在使用ImageView加载图片的地方,配置当前页面的ImageLoader选项。有可能是Activity,也有可能是Adapter。我这个demo是在adapter里面配置DisplayImageOptions对象。代码如下所示:
public class MainActivity extends Activity { // 创建ImageLoader对象 private ImageLoader imageLoader = ImageLoader.getInstance(); private ListView lsv_image_loader; // 网络图片的URL和drawable下的图片,其他的图片(比如手机本地)的URL看我博客有写,这里没有全部给出,大家可以自己去试试看。 private String[] picture_uri = new String[] { "http://pic2.16pic.com/00/15/80/16pic_1580359_b.jpg", "http://pic.58pic.com/58pic/14/21/47/26t58PICywd_1024.jpg", "http://pic.58pic.com/58pic/14/21/42/15T58PICe3i_1024.jpg", "http://pic.58pic.com/58pic/14/21/44/52758PICtw2_1024.jpg", "http://pic.58pic.com/58pic/14/21/32/81U58PICJqm_1024.jpg", "http://pic.58pic.com/58pic/14/21/37/46B58PICudW_1024.jpg", "http://pic.58pic.com/58pic/14/21/39/72g58PICd3K_1024.jpg", "http://img15.3lian.com/2015/f3/08/d/02.jpg", "http://pic.58pic.com/58pic/14/21/47/99N58PICE7q_1024.jpg", "drawable://" + R.drawable.png_11 }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 设置该Activity使用的布局文件 setContentView(R.layout.activity_main); // 获取ListView控件 lsv_image_loader = (ListView) findViewById(R.id.lsv_image_loader); // 创建ImageLoaderBaseAdapter对象 ImageLoaderBaseAdapter adapter = new ImageLoaderBaseAdapter(this); // listView设置adapter lsv_image_loader.setAdapter(adapter); } /** * 自定义ImageLoaderBaseAdapter继承BaseAdapter,重写相关方法 * @author 邹奇 * */ class ImageLoaderBaseAdapter extends BaseAdapter { private LayoutInflater inflater; public ImageLoaderBaseAdapter(Context context) { this.inflater = LayoutInflater.from(context); } @Override public int getCount() { return picture_uri.length; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return picture_uri[position]; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub ViewHolder holder = null; if (convertView == null) { convertView = inflater.inflate(R.layout.lsv_item_image_loader, null); holder = new ViewHolder(); holder.iv_lin = (ImageView) convertView .findViewById(R.id.iv_lin); convertView.setTag(holder); } holder = (ViewHolder) convertView.getTag(); // 创建DisplayImageOptions对象并进行相关选项配置 DisplayImageOptions options = 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 RoundedBitmapDisplayer(20))// 设置成圆角图片 .build();// 创建DisplayImageOptions对象 // 使用ImageLoader加载图片 imageLoader.displayImage(picture_uri[position], holder.iv_lin, options); return convertView; } /** * 控件缓存类 * @author 邹奇 * */ class ViewHolder { ImageView iv_lin; } } @Override protected void onDestroy() { // 回收该页面缓存在内存中的图片 imageLoader.clearMemoryCache(); super.onDestroy(); } }
上面的代码中我都给出了注释,方便大家理解。这里我给出的是网络上的图片的URL和drawable下的图片的URL,比如上面的ImageLoaderBaseAdapter 里,使用ImageLoader对象加载图片的方法如下:
imageLoader.displayImage(picture_uri[position],holder.iv_lin, options);// ImageLoader对象利用图片的URL加载图片
其中displayImage方法的第一个参数是图片的URL,第二个参数是ImageView控件。
一般来说,ImageLoader性能如果有问题,就和这里的配置有关,尤其是ImageLoaderConfiguration。而这里上面的一些配置代码都是目前比较通用的,大家可以参考。
最后给大家讲讲ImageLoader的优化吧!这是我现在正在研读的一本书上面提到的,这里分享给大家。原文如下:
===========================================
尽管ImageLoader很强大,但一直把图片缓存在内存中,会导致内存占用过高。虽然对图片的引用是软引用,软引用在内存不够的时候会被GC,但我们还是希望减少GC的次数,所以要经常手动清理ImageLoader中的缓存。
我们在上面MainActivity的 onDestroy()生命周期方法中,执行了ImageLoader的clearMemoryCache方法,以确保页面销毁时,把为了显示这个页面而增加的内存缓存清除。这样,即使到了下个页面要复用之前加载过的图片,虽然内存中没有了,根据ImageLoader的缓存策略,还是可以在本地磁盘上找到:
@Override protected void onDestroy() { // 回收该页面缓存在内存中的图片 imageLoader.clearMemoryCache(); super.onDestroy(); }
这里加载图片时候,写图片的URL的时候需要注意,图片的URL可以分为以下几种:
// 网络图片 String imageUri = "http://pic2.16pic.com/00/15/80/16pic_1580359_b.jpg"; //SD卡图片 String imageUri = "file:///mnt/sdcard/zouqi.png"; // 媒体文件夹 String imageUri = "content://media/external/audio/albumart/6"; // assets String imageUri = "assets://zouqi.png"; // drawable文件 String imageUri = "drawable://" + R.drawable.zouqi;
好了,所有的配置和方法都讲完了。下面给大家演示一下加载的图片效果:
listView的第一张图片
listView的第二张图片
listView的第三张图片
listView的最后一张图片,最后的小狗图片是drawable下的图片资源
这里我写的demo只加载了网络的和drawable下的图片,其他的图片加载大家就自己去试试看,其实就是URL的写法,这里就不过多讲了,上面有讲到。最后大家别忘了给清单配置文件加网络权限和写权限:
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
ImageLoader的jar包资源:点我下载
加载图片的Demo:点我下载
每天进步一点点!加油!
相关文章推荐
- Android使用ImageLoader异步加载网络图片(二)结合listview
- Android使用ImageLoader异步加载网络图片(一)读取单张图片
- Android 主流网络图片加载缓存库框架Universal-ImageLoader的使用
- Android 使用imageLoader来加载显示图片
- android-----Volley框架使用ImageLoader加载图片源码分析
- 关于android图片加载框架univser-imageloader使用的一些小技巧记录
- Android SmartImageView的使用(堪与ImageLoader加载图片媲美)
- Android 使用ImageLoader框架进行图片加载
- 第十九篇 android使用ImageLoader加载本地图片
- Android图片加载神器之Fresco-加载图片基础[详细图解Fresco的使用](秒杀imageloader)
- Android UI-开源框架ImageLoader完美使用+listview加载网络图片与下载
- Android使用Universal-ImageLoader在ListView中加载网络图片简单示例
- Android开发之使用createFromStream加载图片发现图片变小
- [置顶] Android使用WebView加载图片防止OutOfMemoryError
- 使用ImageLoader实现图片异步加载
- Android 异步加载图片,使用LruCache和SD卡或手机缓存,效果非常的流畅
- [Android] AsyncTask使用实例---加载网络图片
- Android UI开发第三十六篇——使用Volley加载图片列表
- android中图片加载使用LruCache缓存到内存或外部文件的功能
- Android(decode文件转成bitmap)使用BitmapFactory.Options解决加载大图片内存溢出