转载请注明出处:http://blog.csdn.net/u011733020
前言:
在Android开发中,对于图片的载入能够说是个老生常谈的问题了,图片载入是一个比較坑的地方。处理不好,会有各种奇怪的问题,比方 载入导致界面卡顿。程序crash。
因此 怎样高效的载入大量图片。以及怎样载入大分辨率的图片到内存。是我们想要开发一款优质app时不得不去面对与解决的问题。
通常开发中,我们仅仅有两种选择:① 使用开源框架 ②自己去实现处理图片的载入与缓存。
通常一開始让我们自己去写,我们会无从下手,因此先去分析一下开源的思路,对我们的成长非常有必要。
眼下使用频率较高的图片缓存框架有 Universal-Image-Loader、android-Volley、Picasso、Fresco和Glide五大Android开源组件。
首先排除android-Volley 孰优孰劣,后面再去验证。剩下的四种对于 图片载入缓存的思想,从慷慨向上应该是相似的
而Android-Universal-Image-Loader(UIL for short)作为一款比較经典的框架,从早期到如今一直都比較常见,这里就拿UIL来看一下它对图片处理的思想,然后设置写一下自己的imagloader,本文首先介绍一下UIL的基本信息。
正文:
在本文中先介绍一下UIL在Github上的使用介绍。
UIL 在github上的地址https://github.com/nostra13/Android-Universal-Image-Loader 遗憾的是作者在2015.11月已经声明不在维护更新了。
UIL的介绍:Powerful and flexible library for loading, caching and displaying images on Android(高效灵活的载入、缓存以及展示图片)。
以下看一下详细怎么用
Quick Setup
1. Include library
Manual:
- Download JAR
- Put the JAR in the libs subfolder of your Android project
or
Maven dependency:
<dependency> <groupId>com.nostra13.universalimageloader</groupId> <artifactId>universal-image-loader</artifactId> <version>1.9.5</version> </dependency>
or
Gradle dependency:
compile ‘com.nostra13.universalimageloader:universal-image-loader:1.9.5‘
2. Android Manifest
<manifest> <!-- Include following permission if you load images from Internet --> <uses-permission android:name="android.permission.INTERNET" /> <!-- Include following permission if you want to cache images on SD card --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ... </manifest>
3. Application or Activity class (before the first usage of ImageLoader)
public class MyActivity extends Activity { @Override public void onCreate() { super.onCreate(); // Create global configuration and initialize ImageLoader with this config ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this) ... .build(); ImageLoader.getInstance().init(config); ... } }
Configuration
ImageLoader Configuration (ImageLoaderConfiguration
) is global for application. You should set it once.
All options in Configuration builder are optional. Use only those you really want to customize.
See default values for config options in Java docs for every option.
// DON‘T COPY THIS CODE TO YOUR PROJECT! This is just example of ALL options using. // See the sample project how to use ImageLoader correctly. File cacheDir = StorageUtils.getCacheDirectory(context); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context) .memoryCacheExtraOptions(480, 800) // default = device screen dimensions .diskCacheExtraOptions(480, 800, null) .taskExecutor(...) .taskExecutorForCachedImages(...) .threadPoolSize(3) // default .threadPriority(Thread.NORM_PRIORITY - 2) // default .tasksProcessingOrder(QueueProcessingType.FIFO) // default .denyCacheImageMultipleSizesInMemory() .memoryCache(new LruMemoryCache(2 * 1024 * 1024)) .memoryCacheSize(2 * 1024 * 1024) .memoryCacheSizePercentage(13) // default .diskCache(new UnlimitedDiskCache(cacheDir)) // default .diskCacheSize(50 * 1024 * 1024) .diskCacheFileCount(100) .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default .imageDownloader(new BaseImageDownloader(context)) // default .imageDecoder(new BaseImageDecoder()) // default .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default .writeDebugLogs() .build();
Display Options
Display Options (DisplayImageOptions
) are local for every display task (ImageLoader.displayImage(...)
).
Display Options can be applied to every display task (ImageLoader.displayImage(...)
call).
Note: If Display Options wasn‘t passed to ImageLoader.displayImage(...)
method then default Display Options from configuration (ImageLoaderConfiguration.defaultDisplayImageOptions(...)
) will be used.
// DON‘T COPY THIS CODE TO YOUR PROJECT! This is just example of ALL options using. // See the sample project how to use ImageLoader correctly. DisplayImageOptions options = new DisplayImageOptions.Builder() .showImageOnLoading(R.drawable.ic_stub) // resource or drawable .showImageForEmptyUri(R.drawable.ic_empty) // resource or drawable .showImageOnFail(R.drawable.ic_error) // resource or drawable .resetViewBeforeLoading(false) // default .delayBeforeLoading(1000) .cacheInMemory(false) // default .cacheOnDisk(false) // default .preProcessor(...) .postProcessor(...) .extraForDownloader(...) .considerExifParams(false) // default .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default .bitmapConfig(Bitmap.Config.ARGB_8888) // default .decodingOptions(...) .displayer(new SimpleBitmapDisplayer()) // default .handler(new Handler()) // default .build();
Useful Info
- Caching is NOT enabled by default. If you want loaded images to be cached in memory and/or on disk then you should enable caching in DisplayImageOptions this way:
// Create default options which will be used for every // displayImage(...) call if no options will be passed to this method DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder() ... .cacheInMemory(true) .cacheOnDisk(true) ... .build(); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()) ... .defaultDisplayImageOptions(defaultOptions) ... .build(); ImageLoader.getInstance().init(config); // Do it on Application start
// Then later, when you want to display image ImageLoader.getInstance().displayImage(imageUrl, imageView); // Default options will be used
or this way:
DisplayImageOptions options = new DisplayImageOptions.Builder() ... .cacheInMemory(true) .cacheOnDisk(true) ... .build(); ImageLoader.getInstance().displayImage(imageUrl, imageView, options); // Incoming options will be used
- If you enabled disk caching then UIL try to cache images on external storage (/sdcard/Android/data/[package_name]/cache). If external storage is not available then images are cached on device‘s filesystem. To provide caching on external storage (SD card) add following permission to AndroidManifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
- How UIL define Bitmap size needed for exact ImageView?
It searches defined parameters:
- Get actual measured width and height of ImageView
- Get
android:layout_width
andandroid:layout_height
parameters - Get
android:maxWidth
and/orandroid:maxHeight
parameters - Get maximum width and/or height parameters from configuration (
memoryCacheExtraOptions(int, int)
option) - Get width and/or height of device screen
So try to set
android:layout_width
|android:layout_height
orandroid:maxWidth
|android:maxHeight
parameters for ImageView if you know approximate maximum size of it. It will help correctly compute Bitmap size needed for this view and save memory. - If you often got OutOfMemoryError in your app using Universal Image Loader then:
- Disable caching in memory. If OOM is still occurs then it seems your app has a memory leak. Use MemoryAnalyzer to detect it. Otherwise try the following steps (all of them or several):
- Reduce thread pool size in configuration (
.threadPoolSize(...)
). 1 - 5 is recommended. - Use
.bitmapConfig(Bitmap.Config.RGB_565)
in display options. Bitmaps in RGB_565 consume 2 times less memory than in ARGB_8888. - Use
.imageScaleType(ImageScaleType.EXACTLY)
- Use
.diskCacheExtraOptions(480, 320, null)
in configuration
- For memory cache configuration (
ImageLoaderConfiguration.memoryCache(...)
) you can use already prepared implementations.- Cache using only strong references:
LruMemoryCache
(Least recently used bitmap is deleted when cache size limit is exceeded) - Used by default
- Caches using weak and strong references:
UsingFreqLimitedMemoryCache
(Least frequently used bitmap is deleted when cache size limit is exceeded)LRULimitedMemoryCache
(Least recently used bitmap is deleted when cache size limit is exceeded)FIFOLimitedMemoryCache
(FIFO rule is used for deletion when cache size limit is exceeded)LargestLimitedMemoryCache
(The largest bitmap is deleted when cache size limit is exceeded)LimitedAgeMemoryCache
(Decorator. Cached object is deleted when its age exceeds defined value)
- Cache using only weak references:
WeakMemoryCache
(Unlimited cache)
- Cache using only strong references:
- For disk cache configuration (
ImageLoaderConfiguration.diskCache(...)
) you can use already prepared implementations:UnlimitedDiscCache
(The fastest cache, doesn‘t limit cache size) - Used by defaultLruDiskCache
(Cache limited by total cache size and/or by file count. If cache size exceeds specified limit then least-recently used file will be deleted)LimitedAgeDiscCache
(Size-unlimited cache with limited files‘ lifetime. If age of cached file exceeds defined limit then it will be deleted from cache.)
NOTE: UnlimitedDiscCache is pretty faster than other limited disk cache implementations.
- To display bitmap (
DisplayImageOptions.displayer(...)
) you can use already prepared implementations:RoundedBitmapDisplayer
(Displays bitmap with rounded corners)FadeInBitmapDisplayer
(Displays image with "fade in" animation)
- To avoid list (grid, ...) scrolling lags you can use
PauseOnScrollListener
:boolean pauseOnScroll = false; // or true boolean pauseOnFling = true; // or false PauseOnScrollListener listener = new PauseOnScrollListener(imageLoader, pauseOnScroll, pauseOnFling); listView.setOnScrollListener(listener);
- If you see in logs some strange supplement at the end of image URL (e.g.
http://anysite.com/images/image.png_230x460
) then it doesn‘t mean this URL is used in requests. This is just "URL + target size", also this is key for Bitmap in memory cache. This postfix (_230x460
) is NOT used in requests. - ImageLoader always keeps aspect ratio of images.
以上都是UIL在Github的 readme 中提到的使用。以及注意事项,当遇到问题是,先在useful info中看能否找到答案,然后在去找其它解决方式。
将UIL加入到我们的工程中仅仅须要以下三步就可以:
1.下载lib 导入到目标工程。
2.manifest 文件里加入权限。
3.在application 中进行UIL的初始化配置。
然后通过 displayImage(String uri, ImageView imageView) 进行载入图片使用。
UIL特点介绍:
能够通过配置显示圆角图片。
支持多种网络情况下的 载入机制。
仅仅须要传递一个url 就可以(网络、本地都能够)。
将要显示的图片url 与View绑定,避免了图片错位这样的现象。
使用线程池管理任务线程:既保证载入效率,也保证了优化app性能。
设置本地缓存路径。方便后期查看管理缓存文件(清空本地缓存)。
载入高分辨率的图片。自己主动改变bitmap分辨率,降低内存占用防止oom。
支持特殊情况比方滑动过程中暂停载入,停止滑动后,在载入,保证了载入当前页面的效率。
能够加入下载过程的监听,能够设置下载中的默认图片背景,下载完毕后。能够选择显示图片的动画。
实际项目中使用:
以下是在项目中使用的详细介绍:
1.在Application中进行init:
public static void initImageLoader(Context context) { ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder( context) .threadPriority(Thread.NORM_PRIORITY + 2) .denyCacheImageMultipleSizesInMemory() .threadPoolSize(10) .discCacheFileNameGenerator(new Md5FileNameGenerator()) .tasksProcessingOrder(QueueProcessingType.LIFO) .diskCache( new UnlimitedDiskCache(new File(ApplicationData .getPicDir()))) .memoryCache(new LRULimitedMemoryCache(2 * 1024 * 1024)) .build(); ImageLoader.getInstance().init(config); }
2.在要显示图片的地方,比方ListView、GridView的Adapter的getView() 方法中:
imageLoader.displayImage(url, shower, roundShapeOption) ;
而且能够动态传入 须要的option:
options = new DisplayImageOptions.Builder() .showStubImage(R.drawable.trans_pic) .showImageForEmptyUri(R.drawable.trans_pic) .showImageOnFail(R.drawable.trans_pic) .delayBeforeLoading(IMG_LOAD_DELAY) .cacheInMemory(true) .cacheOnDisc(true) .bitmapConfig(Bitmap.Config.RGB_565) //设置图片的解码类型 .build();
怎样在低内存手机上降低OOM的概率:
在低内存的手机上建议以下配置:
对ImageLoaderConfiguration 參数的设置:
降低配置之中线程池的大小(threadPoolSize)
对DisplayImageOptions 參数设置:
imageScaleType(ImageScaleType.IN_SAMPLE_INT)或者 try.imageScaleType(ImageScaleType.EXACTLY)。
.bitmapConfig(Bitmap.Config.RGB_565) //默认是ARGB_8888,使用RGB_565会比使用ARGB_8888少消耗2倍的内。
避免使用RoundedBitmapDisplayer.他会创建新的ARGB_8888格式的Bitmap对象。
使用.memoryCache(new WeakMemoryCache()),不要使用.cacheInMemory()。
依据url 的来源:
http://site.com/image.png // from Web
file:///mnt/sdcard/image.png // from SD card
file:///mnt/sdcard/video.mp4 // from SD card (video thumbnail)
content://media/external/images/media/13 // from content provider
content://media/external/video/media/13 // from content provider (video thumbnail)
assets://image.png // from assets
drawable:// + R.drawable.img // from drawables (non-9patch images)
file:///storage/emulated/0/UIL/Document/pics/aaa.jpg
手机版本号不一致,可能也不一样 ,详细还是要自己灵活区分。
很多其它配置參考:http://www.yq1012.com/android/2053.html 。
本文主要介绍 UIL的基本接入以及 使用配置,有关载入过程,缓存过程,请看下一篇 Android-Universal-Image-Loader (图片异步载入缓存库)的源代码解读
谢谢认真观读本文的每一位小伙伴。衷心欢迎小伙伴给我指出文中的错误,也欢迎小伙伴与我交流学习。
欢迎爱学习的小伙伴加群一起进步:230274309 。