Android图片加载库的理解
ImageLoader的工作原理:在显示图片的时,它会先在内存中查找,如果没有就去本地查找,如果还没有,就开一个新的线程去下载这张图片,下载成功会把图片同时缓存在内存和本地。
我们在基于这个原理,在每次退出一个页面时候,把ImageLoader内存中缓存全部清除,这样就节省了大量内存,反正下次再用到的时候从本地再取出来就行了。需要说明的是,由于ImageLoader对图片是软引用的形式,所以在内存中的图片会存在内存不足的时候被系统回收。
总设计图:
ImageLoader流程图ImageLoader的使用ImageLoader由三大组件组成:
ImagaLoaderConfiguaration——对图片缓存进行总体配置,包含内存缓存的大小,本地缓存的大小和位置、日志、下载策略(FIFO还是LIFO)等。
ImageLoader——一般使用displayImage来把URL对应的图片显示在ImageView上。
DisplayImageOptions——在每个页面需要显示图片的地方,控制如何显示的细节,比如指定下载时的默认图、是否将缓存放到内存或本地磁盘。
从三者的协作关系上看,他们有点像厨房规定、厨师、客户个人口味之间的关系。ImageLoaderConfiguration就像是厨房里面的规定,每一个厨师要怎么着装,要怎么保持厨房的干净,这是针对每一个厨师都适用的规定,而且不允许个性化改变。ImageLoader就像是具体做菜的厨师,负责具体菜谱的制作。DisplayImageOptions就像每个客户的偏好,根据客户是重口味还是清淡,每一个p_w_picpathLoader根据DisplayImageOptions的要求具体执行。
ImagaLoaderConfiguaration示例代码:
//DON'TCOPYTHISCODETOYOURPROJECT!ThisisjustexampleofALLoptionsusing.//SeethesampleprojecthowtouseImageLoadercorrectly.FilecacheDir=StorageUtils.getCacheDirectory(context);ImageLoaderConfigurationconfig=newImageLoaderConfiguration.Builder(context).memoryCacheExtraOptions(480,800)//default=devicescreendimensions.diskCacheExtraOptions(480,800,null).taskExecutor(...).taskExecutorForCachedImages(...).threadPoolSize(3)//default.threadPriority(Thread.NORM_PRIORITY-2)//default.tasksProcessingOrder(QueueProcessingType.FIFO)//default.denyCacheImageMultipleSizesInMemory().memoryCache(newLruMemoryCache(2*1024*1024)).memoryCacheSize(2*1024*1024).memoryCacheSizePercentage(13)//default.diskCache(newUnlimitedDiskCache(cacheDir))//default.diskCacheSize(50*1024*1024).diskCacheFileCount(100).diskCacheFileNameGenerator(newHashCodeFileNameGenerator())//default.p_w_picpathDownloader(newBaseImageDownloader(context))//default.p_w_picpathDecoder(newBaseImageDecoder())//default.defaultDisplayImageOptions(DisplayImageOptions.createSimple())//default.writeDebugLogs().build();
可以看到ImagaLoaderConfiguaration的职责就是记录相关的配置,它的内部就是一些字段的集合。
DisplayImageOptions每一个ImageLoader.displayImage(...)都可以使用DisplayImageOptions,具体配置代码如下:
//DON'TCOPYTHISCODETOYOURPROJECT!ThisisjustexampleofALLoptionsusing.//SeethesampleprojecthowtouseImageLoadercorrectly.DisplayImageOptionsoptions=newDisplayImageOptions.Builder().showImageOnLoading(R.drawable.ic_stub)//resourceordrawable.showImageForEmptyUri(R.drawable.ic_empty)//resourceordrawable.showImageOnFail(R.drawable.ic_error)//resourceordrawable.resetViewBeforeLoading(false)//default.delayBeforeLoading(1000).cacheInMemory(false)//default.cacheOnDisk(false)//default.preProcessor(...).postProcessor(...).extraForDownloader(...).considerExifParams(false)//default.p_w_picpathScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)//default.bitmapConfig(Bitmap.Config.ARGB_8888)//default.decodingOptions(...).displayer(newSimpleBitmapDisplayer())//default.handler(newHandler())//default.build();
ImageLoader最终使用时候,简单几句就行了,传入一个ImageView控件
ImageLoaderp_w_picpathLoader=ImageLoader.getInstance();//Getsingletoninstance//Loadp_w_picpath,decodeittoBitmapanddisplayBitmapinImageView(oranyotherview//whichimplementsImageAwareinterface)p_w_picpathLoader.displayImage(p_w_picpathUri,p_w_picpathView);
又或者直接
//Loadp_w_picpath,decodeittoBitmapandreturnBitmaptocallbackp_w_picpathLoader.loadImage(p_w_picpathUri,newSimpleImageLoadingListener(){@OverridepublicvoidonLoadingComplete(Stringp_w_picpathUri,Viewview,BitmaploadedImage){//DowhateveryouwantwithBitmap}});
ImageLoader优化尽管ImageLoader很强大,但一直把图片缓存在内存中,会导致内存占用过高。虽然对图片的引用是软引用,软引用在内存不够的时候会被GC,但我们还是希望减少GC的次数,所以要经常手动清理ImageLoader中的缓存。
比如,我们经常在做项目的时候,会有一个AppBaseActivity的基类,这样我们可以在基类的onDestroy方法中,执行ImageLoader的clearMemoryCache方法,以确保页面销毁时,把为了显示这个页面而增加的内存缓存清除,这样即使到了下个页面要复用之前加载过的图片,虽然内存没有了,根据ImageLoader的缓存策略,在本地磁盘上还是能被找到的。
比如:
protectedvoidonDestroy(){//回收该页面缓存在内存的图片p_w_picpathLoader.clearMemoryCache();super.onDestroy();}Fresco介绍
简介:
Fresco 是一个强大的图片加载组件。它是Facebook开源的图片加载库
Fresco 中设计有一个叫做p_w_picpath pipeline的模块。它负责从网络,从本地文件系统,本地资源加载图片。为了最大限度节省空间和CPU时间,它含有3级缓存设计(2级内存,1级文件)。
Fresco 中设计有一个叫做Drawees模块,方便地显示loading图,当图片不再显示在屏幕上时,及时地释放内存和空间占用。
Fresco 支持 Android2.3(API level 9) 及其以上系统。
流程图:
原理:
Fresco设计了p_w_picpath pipeline的概念,它负责先后检查内存,磁盘文件,如果都没有再老老实实从网络下载图片。
主要有个三层缓存的概念
第一层:Bitmap缓存
在Android 5.0系统中,考虑到内存管理有了很大改进,所以 Bitmap缓存位于Java的heap中,而在Android 4.X或更低的系统中,Bitmap缓存位于ashmem中,而不是位于Java的heap中,这意味着图片的创建和回收不会引发过多的GC,从而让APP运行的更快。
第二层:内存缓存
内存缓存中存储了图片的原始压缩格式,从内存缓存中取出的图片,在显示前必须先解码,当APP切换到后台时,内存缓存也会被清空。
第三层:磁盘缓存
又名本地缓存,磁盘缓存中存储的也是图片的原始压缩格式,在使用前也要先解码,当APP切换到后台时,磁盘缓存不会丢失,即使关机也不会。
使用:
为了下载网络图片,请确保在AndroidManifest.xml
中有以下权限:
<uses-permissionandroid:name="android.permission.INTERNET"/>
在 Application 初始化时,在应用调用setContentView()
之前,进行初始化:
Fresco.initialize(context);
在xml布局文件中, 加入命名空间:
<!--其他元素--><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:fresco="http://schemas.android.com/apk/res-auto">加入SimpleDraweeView:<com.facebook.drawee.view.SimpleDraweeViewandroid:id="@+id/my_p_w_picpath_view"android:layout_width="20dp"android:layout_height="20dp"fresco:placeholderImage="@drawable/my_drawable"/>
开始加载图片
Uriuri=Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/fresco-logo.png");SimpleDraweeViewdraweeView=(SimpleDraweeView)findViewById(R.id.my_p_w_picpath_view);draweeView.setImageURI(uri);图片策略优化
我们这里说的图片,是根据服务端的接口返回的图片URL地址开启一个线程下载到APP本地并显示的,很多APP崩溃的原因就是图片的问题没处理好。那么就有一些相关解决方案策略,如下。
要确保下载的每张图,都符合ImageView控件的大小。可以事先准备很多套不同的分辨率的图片,然后每次根据URL请求图片时,都要额外在URL上加两个参数,width和height,从而要求服务器返回其中某一个张图,比如:http://www.aaa.com/a.png?width=100&height=50
低流量模式。在2G和3G网络环境下,我们应该适当降低图片的质量,降低图片质量,相应的图片大小也会降低,简称低流量模式,比如在请求网址中再添加一个参数,叫做quality,在2G网络下这个值为50%,在3G网络情况下,这个值为70%,这样就会将JPG图片质量降低为50%或70%。
极速模式。发现在2G和3G网络环境下,大部分用户对图片不感兴趣,我们可以设计一些只有文字的页面,这种页面称呼为极速模式,以节省流量。
小结本篇主要介绍了第三方图片加载库的原理和使用方法,特别是ImageLoader的介绍,因为图片显示在APP中是很常见的应用场景,况且ImageLoader已经封装好了一些类和方法。我们可以直接拿来用了。而不用重复去写了。如果自己去写一个的话,这方面的程序还是比较麻烦的,要考虑多线程缓存,内存溢出等很多方面,再说这么多程序都在用,说明稳定性还是可靠的,类似这种工具类能用稳定成熟的,我们作为一名开发人员,专注度还是在应用业务开发上。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。