Android 映像非同步載入之Android-Universal-Image-Loader
概述:項目地址:https://github.com/nostra13/Android-Universal-Image-Loader UIL(Universal-Image-Loader)非同步映像載入、緩衝和顯示.這個圖片非同步載入並緩衝的類已經被很多開發人員所使用,是最常用的幾個開源庫之一,主流的應用,隨便反編譯幾個火的項目,都可以見到它的身影。 同類類庫(Picasso),儘管Picasso擁有更好的API,但其缺乏自訂。而使用UIL構建器幾乎可以配置所有(其中最重要的就是在抓取和緩衝大型圖片時,Picasso會失敗)。
特點: 多線程載入映像Multithread image loading (async or sync)寬泛的自訂配置Wide customization of ImageLoader's configuration (thread executors, downloader, decoder, memory and disk cache, display image options, etc.)Many customization options for every display image call (stub images, caching switch, decoding options, Bitmap processing and displaying, etc.)映像緩衝Image caching in memory and/or on disk (device's file system or SD card)載入過程監聽Listening loading process (including downloading progress) 簡單描述一下這個項目的結構:每一個圖片的載入和顯示任務都運行在獨立的線程中,除非這個圖片緩衝在記憶體中,這種情況片會立即顯示。如果需要的圖片緩衝在本地,他們會開啟一個獨立的線程隊列。如果在緩衝中沒有正確的圖片,任務線程會從線程池中擷取,因此,快速顯示緩衝圖片時不會有明顯的障礙。
由於源碼中不管是loadImageSync還是loadImage最後都會通過displayImage來載入。那我們看看其流程:
準備工作安裝:maven:
com.nostra13.universalimageloader universal-image-loader 1.9.3
Gradle:
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.3'
添加網路和SD卡許可權:由於是使用過程中會圖片擷取要通過網路,並且有緩衝設定,所以這2個許可權必須要有。
預配置Application or Activity class (before the first usage of ImageLoader)
// Create global configuration and initialize ImageLoader with this config ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this) ... .build(); ImageLoader.getInstance().init(config);
Acceptable URIs examples
http://site.com/image.png // from Webfile:///mnt/sdcard/image.png // from SD cardfile:///mnt/sdcard/video.mp4 // from SD card (video thumbnail)content://media/external/images/media/13 // from content providercontent://media/external/video/media/13 // from content provider (video thumbnail)assets://image.png // from assetsdrawable:// + R.drawable.img // from drawables (non-9patch images)
NOTE: Use drawable:// only if you really need it! Always consider the native way to load drawables - ImageView.setImageResource(...) instead of using of ImageLoader.
樣本
imageLoader.displayImage(imageUri, imageView);imageLoader.loadImage(imageUri, new SimpleImageLoadingListener() { @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { // Do whatever you want with Bitmap }});// Load image, decode it to Bitmap and return Bitmap synchronouslyBitmap bmp = imageLoader.loadImageSync(imageUri);// Load image, decode it to Bitmap and return Bitmap to callbackImageSize targetSize = new ImageSize(80, 50); // result Bitmap will be fit to this sizeimageLoader.loadImage(imageUri, targetSize, options, new SimpleImageLoadingListener() { @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { // Do whatever you want with Bitmap }});// Load image, decode it to Bitmap and return Bitmap synchronouslyImageSize targetSize = new ImageSize(80, 50); // result Bitmap will be fit to this sizeBitmap bmp = imageLoader.loadImageSync(imageUri, targetSize, options);還可以通過
ImageLoadingProgressListener監聽進度。
配置ImageLoaderConfiguration應該是一個對於Application的全域對象,你應該只配置一次。
// 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) //.推薦diskCacheExtraOptions(480, 800, null) .taskExecutor(...) .taskExecutorForCachedImages(...) .threadPoolSize(3) // default 推薦1-5 .threadPriority(Thread.NORM_PRIORITY - 2) // default .tasksProcessingOrder(QueueProcessingType.FIFO) // default .denyCacheImageMultipleSizesInMemory() //設定記憶體緩衝不允許緩衝一張圖片的多個尺寸,預設允許。 .memoryCache(new LruMemoryCache(2 * 1024 * 1024)) //使用強引用的緩衝使用它,不過推薦使用weak與strong引用結合的UsingFreqLimitedMemoryCache或者使用全弱引用的WeakMemoryCache .memoryCacheSize(2 * 1024 * 1024) .memoryCacheSizePercentage(13) // default .diskCache(new UnlimitedDiscCache(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();
樣本配置緩衝目錄
File cacheDir = StorageUtils.getOwnCacheDirectory(getApplicationContext(), imageloader/Cache);
.diskCache(new UnlimitedDiscCache(cacheDir))//自訂緩衝路徑
配置Display Options
// 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 推薦.imageScaleType(ImageScaleType.EXACTLY) 節省記憶體 .bitmapConfig(Bitmap.Config.ARGB_8888) // default 推薦.bitmapConfig(Bitmap.Config.RGB_565)節省記憶體 .decodingOptions(...) .displayer(new SimpleBitmapDisplayer()) // default //推薦使用RoundedBitmapDisplayer (Displays bitmap with rounded corners)和FadeInBitmapDisplayer (Displays image with fade in animation .handler(new Handler()) // default .build();
以上配置中的:
1).imageScaleType(ImageScaleType imageScaleType) 是設定 圖片的縮放方式
縮放類型mageScaleType:
EXACTLY :映像將完全按比例縮小的目標大小
EXACTLY_STRETCHED:圖片會縮放到目標大小完全
IN_SAMPLE_INT:映像將被二次採樣的整數倍
IN_SAMPLE_POWER_OF_2:圖片將降低2倍,直到下一減少步驟,使映像更小的目標大小
NONE:圖片不會調整
2).displayer(BitmapDisplayer displayer) 是設定 圖片的顯示方式
顯示方式displayer:
RoundedBitmapDisplayer(int roundPixels)
設定圓角圖片
FakeBitmapDisplayer()這個類什麼都沒做
FadeInBitmapDisplayer(int durationMillis)設定圖片漸顯的時間
SimpleBitmapDisplayer()正常顯示一張圖片
注意的問題
1、緩衝預設情況下是沒有啟用的。可以通過配置DisplayImageOptions來啟用。
// Create default options which will be used for every // displayImage(...) call if no options will be passed to this methodDisplayImageOptions defaultOptions = new DisplayImageOptions.Builder() ... .cacheInMemory(true) .cacheOnDisk(true)
boolean pauseOnScroll = false; // or true boolean pauseOnFling = true; // or false PauseOnScrollListener listener = new PauseOnScrollListener(imageLoader, pauseOnScroll, pauseOnFling); listView.setOnScrollListener(listener);
... .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 imageImageLoader.getInstance().displayImage(imageUrl, imageView); // Default options will be used
或者通過如下方式:
DisplayImageOptions options = new DisplayImageOptions.Builder() ... .cacheInMemory(true) .cacheOnDisk(true) ... .build();ImageLoader.getInstance().displayImage(imageUrl, imageView, options); // Incoming options will be used
2、為了防止list(listview,grid等)滾動遲鈍,可以使用PauseOnScrollListener
boolean pauseOnScroll = false; // or trueboolean pauseOnFling = true; // or falsePauseOnScrollListener listener = new PauseOnScrollListener(imageLoader, pauseOnScroll, pauseOnFling);listView.setOnScrollListener(listener);
幾點注意事項1.
上述提到的2個許可權必須加入,否則會出錯
2
.ImageLoaderConfiguration必須配置並且全域化的初始化這個配置ImageLoader.getInstance().init(config); 否則也會出現錯誤提示
3.ImageLoader是根據ImageView的height,width確定圖片的寬高。
4.如果經常出現OOM(別人那邊看到的,覺得很有提的必要)
①減少配置之中線程池的大小,(.threadPoolSize).推薦1-5;
②使用.bitmapConfig(Bitmap.config.RGB_565)代替ARGB_8888;
③使用.imageScaleType(ImageScaleType.IN_SAMPLE_INT)或者 try.imageScaleType(ImageScaleType.EXACTLY);
④避免使用RoundedBitmapDisplayer.他會建立新的ARGB_8888格式的Bitmap對象;
⑤使用.memoryCache(new WeakMemoryCache()),不要使用.cacheInMemory();