ImageLoader詳解(簡單使用,源碼分析,策略理解)
整體流程
簡單使用
ImageLoaderConfiguration:全局配置:主要有線程類、緩存大小、磁盤大小、圖片下載與解析的配置。
DisplayImageOptions:與展示圖片相關的配置
ImageLoader:具體執行類,最終通過displayImage方法執行
//DisplayImageOptions相關設置
DisplayImageOptions options = new DisplayImageOptions.Builder().showImageOnLoading(R.drawable.loading)
// 設置圖片在下載期間顯示的圖片
.showImageForEmptyUri(R.drawable.ic_launcher)
// 設置圖片Uri爲空或是錯誤的時候顯示的圖片
.showImageOnFail(R.drawable.error)
// 設置圖片加載/解碼過程中錯誤時候顯示的圖片
.cacheInMemory(true)
// 設置下載的圖片是否緩存在內存中
.cacheOnDisk(true)
// 設置下載的圖片是否緩存在SD卡中
.considerExifParams(true)
// 是否考慮JPEG圖像EXIF參數(旋轉,翻轉)
.imageScaleType(ImageScaleType.IN_SAMPLE_INT)
// 設置圖片以如何的編碼方式顯示
.bitmapConfig(Bitmap.Config.RGB_565)
// 設置圖片的解碼類型
// .decodingOptions(BitmapFactory.Options decodingOptions)
// 設置圖片的解碼配置
.delayBeforeLoading(0)
// int delayInMillis爲你設置的下載前的延遲時間
// 設置圖片加入緩存前,對bitmap進行設置
// .preProcessor(BitmapProcessor preProcessor)
.resetViewBeforeLoading(true)
// 設置圖片在下載前是否重置,復位
.displayer(new RoundedBitmapDisplayer(20))
// 不推薦用!!!!是否設置爲圓角,弧度爲多少
.displayer(new FadeInBitmapDisplayer(100))
// 是否圖片加載好後漸入的動畫時間,可能會出現閃動
.build();// 構建完成
//ImageLoaderConfiguration相關設置
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
// 線程池內加載的數量
.threadPoolSize(3)
// 線程優先級
.threadPriority(Thread.NORM_PRIORITY - 2)
// 不允許緩存一張圖片的不同尺寸
.denyCacheImageMultipleSizesInMemory()
// 設置內存緩存,可以自定義實現
.memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024))
// 內存緩存最大值
.memoryCacheSize(2 * 1024 * 1024)
// 磁盤緩存最大值
.diskCacheSize(50 * 1024 * 1024)
// 磁盤緩存文件名生成器
.diskCacheFileNameGenerator(new Md5FileNameGenerator())
// 設置任務的執行順序
.tasksProcessingOrder(QueueProcessingType.LIFO)
// 緩存的文件數量
.diskCacheFileCount(100)
// 默認的顯示設置
.defaultDisplayImageOptions(DisplayImageOptions.createSimple())
// 設置加載器
.imageDownloader(new BaseImageDownloader(context, 5 * 1000, 30 * 1000))
// log
.writeDebugLogs()
// 開始構建
.build();
//使用
ImageLoader.getInstance().init(config);
ImageLoader.getInstance().displayImage(bannerModel.getImageUrl(), imageView,options);
源碼解析
包結構大致如下:僅對部分功能講解
download包:封裝了圖片下載相關的方式
//ImageDownloader類中
public static enum Scheme {
HTTP("http"),
HTTPS("https"),
FILE("file"),
CONTENT("content"),
ASSETS("assets"),
DRAWABLE("drawable"),
UNKNOWN("");
該接口中可以看到可以從網絡,文件,content,assets目錄,drawable目錄去下載文件
BaseImageDownloader爲具體實現類(SlowNetworkImageDownloader NetworkDeniedImageDownloader在其他目錄,後面再講)
public InputStream getStream(String imageUri, Object extra) throws IOException {
switch(Scheme.ofUri(imageUri)) {
case HTTP:
case HTTPS:
//網絡資源從網絡下載,重定向小於5次
return this.getStreamFromNetwork(imageUri, extra);
case FILE:
//File資源從文件下載(爲視頻URi時使用視頻縮略圖)
return this.getStreamFromFile(imageUri, extra);
case CONTENT:
//content資源通過contentresolver獲得(爲視頻URi時使用視頻縮略圖,聯繫人的URI獲取聯繫人縮略圖)
return this.getStreamFromContent(imageUri, extra);
case ASSETS://Assert,drawable 資源正常獲取。
return this.getStreamFromAssets(imageUri, extra);
case DRAWABLE:
return this.getStreamFromDrawable(imageUri, extra);
case UNKNOWN:
default:
return this.getStreamFromOtherSource(imageUri, extra);
}
}
display包:封裝簡單的對展示圖片的屬性的處理(變圓形,圓角矩形,漸入動畫,內陰影等)
通過實現自定義的Drawable,重寫draw方法,使用BitmapShader將bitmap與paint綁定,將其繪製在自定義的不同形狀的Canvas上,重寫onBoundsChange方法,來控制繪製區域的大小,使其更合理的展示出來。
imageWare包:對ImageView的一層包裝,方便內部擴展,如動畫的效果。
protected void setImageDrawableInto(Drawable drawable, View view) {
((ImageView)view).setImageDrawable(drawable);
if (drawable instanceof AnimationDrawable) {
//此處開始動畫
((AnimationDrawable)drawable).start();
}
}
相關策略
網絡下載策略
ImageLoader對不同的網絡狀態下處理下載策略是不同的,主要分爲三種網絡(正常、慢速、無網絡權限),針對三種網絡,實現了三種策略(BaseImageDownloader,SlowNetworkImageDownloader,NetworkDeniedImageDownloader )
BaseImageDownloader如上描述,處理正常網絡情況以及其他的情況
SlowNetworkImageDownloader
private static class SlowNetworkImageDownloader implements ImageDownloader {
private final ImageDownloader wrappedDownloader;
public SlowNetworkImageDownloader(ImageDownloader wrappedDownloader) {
this.wrappedDownloader = wrappedDownloader;
}
public InputStream getStream(String imageUri, Object extra) throws IOException {
InputStream imageStream = this.wrappedDownloader.getStream(imageUri, extra);
switch(Scheme.ofUri(imageUri)) {
case HTTP:
case HTTPS:
return new FlushedInputStream(imageStream);
default:
return imageStream;
}
}
}
//FlushedInputStream類
public class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}
public long skip(long n) throws IOException {
long totalBytesSkipped;
long bytesSkipped;
for(totalBytesSkipped = 0L; totalBytesSkipped < n; totalBytesSkipped += bytesSkipped) {
bytesSkipped = this.in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int by_te = this.read();
if (by_te < 0) {
break;
}
bytesSkipped = 1L;
}
}
return totalBytesSkipped;
}
}
可見慢網情況下使用了FilterInputStream,重寫了skip方法,具體的好處大家可以百度,這裏就不過多解釋了
NetworkDeniedImageDownloader
private static class NetworkDeniedImageDownloader implements ImageDownloader {
private final ImageDownloader wrappedDownloader;
public NetworkDeniedImageDownloader(ImageDownloader wrappedDownloader) {
this.wrappedDownloader = wrappedDownloader;
}
public InputStream getStream(String imageUri, Object extra) throws IOException {
switch(Scheme.ofUri(imageUri)) {
case HTTP:
case HTTPS:
throw new IllegalStateException();
default:
return this.wrappedDownloader.getStream(imageUri, extra);
}
}
}
可見,在無權限的情況下,訪問網絡的直接拋異常,其他類型的則不影響處理
線程池策略
未完待續。。。