安卓基礎(chǔ)開(kāi)發(fā)庫(kù)作谚,讓開(kāi)發(fā)簡(jiǎn)單點(diǎn)型型。
DevRing & Demo地址:https://github.com/LJYcoder/DevRing
學(xué)習(xí)/參考地址:
https://www.fresco-cn.org/docs/index.html
http://blog.csdn.net/wyb112233/article/details/49637685
http://blog.csdn.net/android_ls/article/details/53137867
前言
Fresco是一個(gè)出自Facebook的功能強(qiáng)大的圖片加載庫(kù)
優(yōu)點(diǎn):
1)內(nèi)存自動(dòng)回收。圖片不可見(jiàn)時(shí)犹菇,會(huì)及時(shí)自動(dòng)釋放所占用的內(nèi)存德迹,盡可能地避免OOM
2)三級(jí)緩存機(jī)制。兩級(jí)內(nèi)存緩存(解碼的與未解碼的)+一級(jí)磁盤緩存揭芍,提升加載速度胳搞,節(jié)省內(nèi)存占用空間
3)支持各種加載場(chǎng)景。如動(dòng)圖加載称杨、高斯模糊等常見(jiàn)的圖片加載場(chǎng)景肌毅。另外還提供了獨(dú)特的漸進(jìn)式加載、先加載小圖再加載大圖姑原,加載進(jìn)度等功能(很強(qiáng)大)悬而。
缺點(diǎn):
1)體積大(很胖)。較其他主流圖片庫(kù)體積要大不少
2)侵入性較強(qiáng)锭汛。須使用它提供的SimpleDraweeView來(lái)代替ImageView加載顯示圖片
綜合來(lái)說(shuō)笨奠,如果你的應(yīng)用對(duì)圖片的顯示袭蝗、加載等要求高的話,那就建議使用Fresco艰躺。但如果要求沒(méi)那么高的話就用Glide或其它庫(kù)吧呻袭。
關(guān)于Fresco與Glide的對(duì)比可以參考http://www.reibang.com/p/6729dc17586b
介紹
下面通過(guò) 配置、SimpleDraweeView腺兴、加載圖片、混淆廉侧、其他 這幾個(gè)部分來(lái)介紹页响。
1. 配置
1.1 添加依賴
compile 'com.facebook.fresco:fresco:1.5.0'
compile 'com.facebook.fresco:animated-gif:1.5.0'//加載gif動(dòng)圖需添加此庫(kù)
compile 'com.facebook.fresco:animated-webp:1.5.0'//加載webp動(dòng)圖需添加此庫(kù)
compile 'com.facebook.fresco:webpsupport:1.5.0'//支持webp需添加此庫(kù)
compile 'com.facebook.fresco:imagepipeline-okhttp3:1.5.0'//網(wǎng)絡(luò)實(shí)現(xiàn)層使用okhttp3需添加此庫(kù)
compile 'jp.wasabeef:fresco-processors:2.1.0@aar'//用于提供fresco的各種圖片變換
1.2 設(shè)置磁盤緩存
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setMainDiskCacheConfig(DiskCacheConfig.newBuilder(context)
.setBaseDirectoryPath(context.getExternalCacheDir())//設(shè)置磁盤緩存的路徑
.setBaseDirectoryName(BaseConstants.APP_IMAGE)//設(shè)置磁盤緩存文件夾的名稱
.setMaxCacheSize(MAX_DISK_CACHE_SIZE)//設(shè)置磁盤緩存的大小
.build());
1.3 設(shè)置內(nèi)存緩存
設(shè)置已解碼的內(nèi)存緩存(Bitmap緩存)
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setBitmapMemoryCacheParamsSupplier(new Supplier<MemoryCacheParams>() {
public MemoryCacheParams get() {
int MAX_HEAP_SIZE = (int) Runtime.getRuntime().maxMemory();
int MAX_MEMORY_CACHE_SIZE = MAX_HEAP_SIZE / 5;//取手機(jī)內(nèi)存最大值的五分之一作為可用的最大內(nèi)存數(shù)
MemoryCacheParams bitmapCacheParams = new MemoryCacheParams( //
// 可用最大內(nèi)存數(shù),以字節(jié)為單位
MAX_MEMORY_CACHE_SIZE,
// 內(nèi)存中允許的最多圖片數(shù)量
Integer.MAX_VALUE,
// 內(nèi)存中準(zhǔn)備清理但是尚未刪除的總圖片所可用的最大內(nèi)存數(shù)段誊,以字節(jié)為單位
MAX_MEMORY_CACHE_SIZE,
// 內(nèi)存中準(zhǔn)備清除的圖片最大數(shù)量
Integer.MAX_VALUE,
// 內(nèi)存中單圖片的最大大小
Integer.MAX_VALUE);
return bitmapCacheParams;
}
});
設(shè)置未解碼的內(nèi)存緩存
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setEncodedMemoryCacheParamsSupplier(new Supplier<MemoryCacheParams>() {
public MemoryCacheParams get() {
MemoryCacheParams bitmapCacheParams;
//設(shè)置大小闰蚕,可參考上面已解碼的內(nèi)存緩存
return bitmapCacheParams;
}
});
1.4 設(shè)置內(nèi)存緊張時(shí)的應(yīng)對(duì)措施
MemoryTrimmableRegistry memoryTrimmableRegistry = NoOpMemoryTrimmableRegistry.getInstance();
memoryTrimmableRegistry.registerMemoryTrimmable(new MemoryTrimmable() {
@Override
public void trim(MemoryTrimType trimType) {
final double suggestedTrimRatio = trimType.getSuggestedTrimRatio();
if (MemoryTrimType.OnCloseToDalvikHeapLimit.getSuggestedTrimRatio() == suggestedTrimRatio
|| MemoryTrimType.OnSystemLowMemoryWhileAppInBackground.getSuggestedTrimRatio() == suggestedTrimRatio
|| MemoryTrimType.OnSystemLowMemoryWhileAppInForeground.getSuggestedTrimRatio() == suggestedTrimRatio) {
//清空內(nèi)存緩存
ImagePipelineFactory.getInstance().getImagePipeline().clearMemoryCaches();
}
}
});
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setMemoryTrimmableRegistry(memoryTrimmableRegistry);
1.5 設(shè)置漸進(jìn)式顯示的效果
ProgressiveJpegConfig progressiveJpegConfig = new ProgressiveJpegConfig() {
@Override
public int getNextScanNumberToDecode(int scanNumber) {
//返回下一個(gè)需要解碼的掃描次數(shù)
return scanNumber + 2;
}
public QualityInfo getQualityInfo(int scanNumber) {
boolean isGoodEnough = (scanNumber >= 5);
//確定多少個(gè)掃描次數(shù)之后的圖片才能開(kāi)始顯示。
return ImmutableQualityInfo.of(scanNumber, isGoodEnough, false);
}
};
//具體含義可參考 http://wiki.jikexueyuan.com/project/fresco/progressive-jpegs.html
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setProgressiveJpegConfig(progressiveJpegConfig);
//或者使用默認(rèn)的效果
//imagePipelineConfigBuilder.setProgressiveJpegConfig(new SimpleProgressiveJpegConfig());
設(shè)置完效果后连舍,還需在下面介紹的ImageRequest中開(kāi)啟漸進(jìn)式加載没陡。
1.6 允許解碼時(shí)調(diào)整圖片大小
允許后,即可在后面介紹的ImageRequest中對(duì)結(jié)合ResizeOptions對(duì)解碼后的圖片大小進(jìn)行調(diào)整索赏,從而優(yōu)化了圖片所占大小盼玄。默認(rèn)只支持JPEG圖,所以要設(shè)置該屬性來(lái)支持png潜腻、jpg埃儿、webp。
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setDownsampleEnabled(true);
1.7 開(kāi)啟Log
FLog.setMinimumLoggingLevel(FLog.VERBOSE);
Set<RequestListener> requestListeners = new HashSet<>();
requestListeners.add(new RequestLoggingListener());
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setRequestListeners(requestListeners);
1.8 初始化
上面的各種配置都是通過(guò)ImagePipelineConfig進(jìn)行的融涣,接著需要進(jìn)行初始化童番,在Application中初始化即可
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
//...進(jìn)行各種設(shè)置
ImagePipelineConfig config = imagePipelineConfigBuilder.build();
Fresco.initialize(context, config);
如果想直接使用默認(rèn)的配置,可以
Fresco.initialize(context);
2. SimpleDraweeView
Fresco要求使用SimpleDraweeView來(lái)替換ImageView進(jìn)行圖片的加載與顯示威鹿,不少人也是因?yàn)檫@一點(diǎn)而不想使用Fresco剃斧。
下面介紹SimpleDraweeView在xml中的各種屬性
//在最外層布局的屬性中加入xmlns:fresco="http://schemas.android.com/apk/res-auto"
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv"
android:layout_width="150dp"
android:layout_height="150dp"
fresco:actualImageScaleType="centerCrop"
fresco:fadeDuration="2000"
fresco:failureImage="@mipmap/ic_launcher"
fresco:failureImageScaleType="centerCrop"
fresco:placeholderImage="@mipmap/ic_launcher"
fresco:placeholderImageScaleType="centerCrop"
fresco:progressBarAutoRotateInterval="1500"
fresco:progressBarImage="@drawable/rotate"
fresco:progressBarImageScaleType="centerCrop"
fresco:retryImage="@mipmap/ic_launcher"
fresco:retryImageScaleType="centerCrop"
fresco:backgroundImage="@mipmap/ic_launcher"
fresco:overlayImage="@mipmap/ic_launcher"
fresco:pressedStateOverlayImage="@mipmap/ic_launcher"
fresco:roundAsCircle="false"
fresco:roundedCornerRadius="7dp"
fresco:roundTopLeft="true"
fresco:roundTopRight="false"
fresco:roundBottomLeft="false"
fresco:roundBottomRight="true"
fresco:roundWithOverlayColor="@color/colorAccent"
fresco:roundingBorderWidth="2dp"
fresco:roundingBorderColor="@color/colorPrimary"
fresco:viewAspectRatio="1"/>
上面各個(gè)屬性的作用說(shuō)明:(來(lái)自http://www.reibang.com/p/8ff81be83101)
屬性 | 作用說(shuō)明 |
---|---|
actualImageScaleType | 加載完成的圖片的縮放樣式 |
fadeDuration | 由進(jìn)度條和占位符圖片漸變過(guò)渡到加載完成的圖片所使用的時(shí)間間隔 |
failureImage | 加載失敗所使用的圖片 |
failureImageScaleType | 加載失敗所使用的圖片的縮放樣式 |
placeholderImage | 占位符圖片 |
placeholderImageScaleType | 占位符圖片的縮放樣式 |
progressBarAutoRotateInterval | 旋轉(zhuǎn)進(jìn)度條旋轉(zhuǎn)1圈所需要的時(shí)間 |
progressBarImage | 旋轉(zhuǎn)進(jìn)度條所使用的圖片 |
progressBarImageScaleType | 旋轉(zhuǎn)進(jìn)度條所使用的圖片的縮放樣式 |
retryImage | 重試所使用的圖片 |
retryImageScaleType | 重試所使用的圖片的縮放樣式 |
backgroundImage | 背景圖片 |
overlayImage | 覆蓋在加載完成后圖片上的疊加圖片 |
pressedStateOverlayImage | 按壓狀態(tài)下的疊加圖片 |
roundAsCircle | 是否將圖片剪切為圓形 |
roundedCornerRadius | 圓角圖片時(shí)候,圓角的半徑大小 |
roundTopLeft | 左上角是否為圓角 |
roundTopRight | 右上角是否為圓角 |
roundBottomLeft | 左下角是否為圓角 |
roundBottomRight | 右下角是否為圓角 |
roundWithOverlayColor | 圓角或圓形圖疊加的顏色忽你,只能是顏色 |
roundingBorderWidth | 圓角或圓形圖邊框的寬度 |
roundingBorderColor | 圓角或圓形圖邊框的顏色 |
viewAspectRatio | 設(shè)置寬高比 |
各個(gè)屬性的效果圖幼东,可到http://blog.csdn.net/wyb112233/article/details/49637685查看,我就不重復(fù)造輪子了檀夹。
*注意:
1)android:src屬性對(duì)于SimpleDraweeView無(wú)效筋粗,必要的話可用fresco:placeholderImage來(lái)設(shè)置。
2)SimpleDraweeView不支持android:layout_width和android:layout_height同時(shí)都設(shè)為wrap_content炸渡。
3. 加載圖片
使用Fresco加載圖片娜亿,大致是按以下流程進(jìn)行的。
- 設(shè)置Hierarchay(上面xml中的屬性以及顯示加載進(jìn)度條等蚌堵,可在這進(jìn)行設(shè)置)
- 構(gòu)建ImageRequest(加載路徑买决、開(kāi)啟漸進(jìn)式加載沛婴、圖片變換、調(diào)整解碼圖片大小等督赤,可在這進(jìn)行設(shè)置)
- 構(gòu)建DraweeController(動(dòng)圖加載嘁灯、失敗后點(diǎn)擊重新加載等,可在這進(jìn)行設(shè)置)
- 進(jìn)行圖片加載
3.1 設(shè)置Hierarchay
雖然xml中的屬性都能在這一步通過(guò)代碼進(jìn)行設(shè)置躲舌,但一般只在這設(shè)置一些統(tǒng)一固定的屬性丑婿,比如加載占位圖、加載失敗圖等没卸。 另外羹奉,顯示圖片的加載進(jìn)度也是在這里設(shè)置。
Resources res = MyApplication.getInstance().getResources();
Drawable retryImage = ResourcesCompat.getDrawable(res, R.mipmap.ic_image_load, null);
Drawable failureImage = ResourcesCompat.getDrawable(res, R.mipmap.ic_image_load, null);
Drawable placeholderImage = ResourcesCompat.getDrawable(res, R.mipmap.ic_image_load, null);
//對(duì)Hierarchy進(jìn)行設(shè)置约计,如各種狀態(tài)下顯示的圖片
public void setHierarchay(GenericDraweeHierarchy hierarchy) {
if (hierarchy != null) {
//重新加載顯示的圖片
hierarchy.setRetryImage(retryImage);
//加載失敗顯示的圖片
hierarchy.setFailureImage(failureImage, ScalingUtils.ScaleType.CENTER_CROP);
//加載完成前顯示的占位圖
hierarchy.setPlaceholderImage(placeholderImage, ScalingUtils.ScaleType.CENTER_CROP);
//設(shè)置加載成功后圖片的縮放模式
hierarchy.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP);
//顯示加載進(jìn)度條诀拭,使用自帶的new ProgressBarDrawable()
//默認(rèn)會(huì)顯示在圖片的底部,可以設(shè)置進(jìn)度條的顏色煤蚌。
hierarchy.setProgressBarImage(new ProgressBarDrawable());
//設(shè)置圖片加載為圓形
hierarchy.setRoundingParams(RoundingParams.asCircle());
//設(shè)置圖片加載為圓角耕挨,并可設(shè)置圓角大小
hierarchy.setRoundingParams(RoundingParams.fromCornersRadius(radius));
//其他設(shè)置請(qǐng)查看具體API。
}
}
3.2 構(gòu)建ImageRequest
/**
* 構(gòu)建尉桩、獲取ImageRequest
* @param uri 加載路徑
* @param simpleDraweeView 加載的圖片控件
* @return ImageRequest
*/
public ImageRequest getImageRequest(Uri uri, SimpleDraweeView simpleDraweeView) {
int width;
int height;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
width = simpleDraweeView.getWidth();
height = simpleDraweeView.getHeight();
} else {
width = simpleDraweeView.getMaxWidth();
height = simpleDraweeView.getMaxHeight();
}
//根據(jù)請(qǐng)求路徑生成ImageRequest的構(gòu)造者
ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
//調(diào)整解碼圖片的大小
if (width > 0 && height > 0) {
builder.setResizeOptions(new ResizeOptions(width, height));
}
//設(shè)置是否開(kāi)啟漸進(jìn)式加載筒占,僅支持JPEG圖片
builder.setProgressiveRenderingEnabled(true);
//圖片變換處理
CombinePostProcessors.Builder processorBuilder = new CombinePostProcessors.Builder();
//加入模糊變換
processorBuilder.add(new BlurPostprocessor(context, radius));
//加入灰白變換
processorBuilder.add(new GrayscalePostprocessor());
//應(yīng)用加入的變換
builder.setPostprocessor(processorBuilder.build());
//更多圖片變換請(qǐng)查看https://github.com/wasabeef/fresco-processors
return builder.build();
}
3.3 構(gòu)建DraweeController
/**
* 構(gòu)建、獲取Controller
* @param request
* @param oldController
* @return
*/
public DraweeController getController(ImageRequest request, @Nullable DraweeController oldController) {
PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder();
builder.setImageRequest(request);//設(shè)置圖片請(qǐng)求
builder.setTapToRetryEnabled(false);//設(shè)置是否允許加載失敗時(shí)點(diǎn)擊再次加載
builder.setAutoPlayAnimations(true);//設(shè)置是否允許動(dòng)畫圖自動(dòng)播放
builder.setOldController(oldController);
return builder.build();
}
3.4 進(jìn)行圖片加載
創(chuàng)建一個(gè)loadImage方法將上面的Hierarchy魄健、ImageRequest赋铝、DraweeController串在一起,供具體的加載場(chǎng)景使用
/**
* 加載圖片核心方法
*
* @param simpleDraweeView 圖片加載控件
* @param uri 圖片加載地址
*/
public void loadImage(SimpleDraweeView simpleDraweeView, Uri uri) {
//設(shè)置Hierarchy
setHierarchay(simpleDraweeView.getHierarchy());
//構(gòu)建并獲取ImageRequest
ImageRequest imageRequest = getImageRequest(uri, simpleDraweeView);
//構(gòu)建并獲取Controller
DraweeController draweeController = getController(imageRequest, simpleDraweeView.getController());
//開(kāi)始加載
simpleDraweeView.setController(draweeController);
}
具體的加載場(chǎng)景:
- 加載網(wǎng)絡(luò)圖片沽瘦,包括gif/webp動(dòng)圖
public void loadNetImage(SimpleDraweeView simpleDraweeView, String url) {
Uri uri = Uri.parse(url);
loadImage(simpleDraweeView, uri);
}
- 加載本地文件圖片
public void loadLocalImage(SimpleDraweeView simpleDraweeView, String fileName) {
Uri uri = Uri.parse("file://" + fileName);
loadImage(simpleDraweeView, uri);
}
- 加載res下資源圖片
public void loadResourceImage(SimpleDraweeView simpleDraweeView, @DrawableRes int resId) {
Uri uri = Uri.parse("res:///" + resId);
loadImage(simpleDraweeView, uri);
}
- 加載ContentProvider下的圖片
public void loadContentProviderImage(SimpleDraweeView simpleDraweeView, int resId) {
Uri uri = Uri.parse("content:///" + resId);
loadImage(simpleDraweeView, uri);
}
- 加載asset下的圖片
public void loadAssetImage(SimpleDraweeView simpleDraweeView, int resId) {
Uri uri = Uri.parse("asset:///" + resId);
loadImage(simpleDraweeView, uri);
}
- 加載網(wǎng)絡(luò)圖片革骨,先加載小圖,待大圖加載完成后再替換掉小圖
這個(gè)需要修改一下DraweeController的構(gòu)建析恋,通過(guò)setLowResImageRequest來(lái)添加小圖請(qǐng)求
public DraweeController getSmallToBigController(ImageRequest smallRequest, ImageRequest bigRequest, @Nullable DraweeController oldController) {
PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder();
builder.setLowResImageRequest(smallRequest);//小圖的圖片請(qǐng)求
builder.setImageRequest(bigRequest);//大圖的圖片請(qǐng)求
builder.setTapToRetryEnabled(false);//設(shè)置是否允許加載失敗時(shí)點(diǎn)擊再次加載
builder.setAutoPlayAnimations(true);//設(shè)置是否允許動(dòng)畫圖自動(dòng)播放
builder.setOldController(oldController);
return builder.build();
}
public void loadImageSmallToBig(SimpleDraweeView simpleDraweeView, Uri smallUri, Uri bigUri) {
//設(shè)置Hierarchy
setHierarchay(simpleDraweeView.getHierarchy());
//構(gòu)建小圖的圖片請(qǐng)求
ImageRequest smallRequest = getImageRequest(smallUri, simpleDraweeView);
//構(gòu)建大圖的圖片請(qǐng)求
ImageRequest bigRequest = getImageRequest(bigUri, simpleDraweeView);
//構(gòu)建Controller
DraweeController draweeController = getSmallToBigController(smallRequest, bigRequest, simpleDraweeView.getController());
//開(kāi)始加載
simpleDraweeView.setController(draweeController);
}
//加載網(wǎng)絡(luò)圖片良哲,先加載小圖,待大圖加載完成后替換
public void loadNetImageSmallToBig(SimpleDraweeView simpleDraweeView, String smallUrl, String bigUrl) {
Uri smallUri = Uri.parse(smallUrl);
Uri bigUri = Uri.parse(bigUrl);
loadImageSmallToBig(simpleDraweeView, smallUri, bigUri);
}
4. 混淆
在proguard-rules.pro文件中添加以下內(nèi)容進(jìn)行混淆配置
#fresco開(kāi)始
-keep class com.facebook.fresco.** { *; }
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
-keep @com.facebook.common.internal.DoNotStrip class *
-keepclassmembers class * {
@com.facebook.common.internal.DoNotStrip *;
}
-keep class com.facebook.imagepipeline.gif.** { *; }
-keep class com.facebook.imagepipeline.webp.* { *; }
-keepclassmembers class * {
native <methods>;
}
-dontwarn okio.**
-dontwarn com.squareup.okhttp.**
-dontwarn okhttp3.**
-dontwarn javax.annotation.**
-dontwarn com.android.volley.toolbox.**
-keep class com.facebook.imagepipeline.animated.factory.AnimatedFactoryImpl {
public AnimatedFactoryImpl(com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory,com.facebook.imagepipeline.core.ExecutorSupplier);
}
#fresco結(jié)束
5. 其他
5.1 緩存策略
Fresco采用三級(jí)緩存機(jī)制助隧,兩級(jí)內(nèi)存緩存+一級(jí)磁盤緩存筑凫,其中兩級(jí)內(nèi)存緩存分為已解碼的圖片緩存(Bitmap緩存)和未解碼的圖片緩存。
下面通過(guò)加載流程來(lái)了解其緩存策略并村。
- 根據(jù)Uri到已解碼的圖片緩存中查找是否存在對(duì)應(yīng)的Bitmap巍实。如果存在,則返回Bitmap顯示哩牍;
如果不存在棚潦,則到未解碼的圖片緩存中查找。 - 如果在未解碼的圖片緩存中存在對(duì)應(yīng)的數(shù)據(jù)膝昆,則解碼丸边,返回Bitmap顯示并將其加入到已解碼的圖片緩存中叠必;如果不存在,則到磁盤緩存中查找妹窖。
- 如果在磁盤緩存中存在對(duì)應(yīng)的數(shù)據(jù)纬朝,則將數(shù)據(jù)加入到未解碼的圖片緩存中,然后解碼骄呼,返回Bitmap顯示并將其加入到已解碼的圖片緩存中共苛;如果不存在,則進(jìn)行網(wǎng)絡(luò)請(qǐng)求或者到本地文件加載谒麦。
- 請(qǐng)求或加載成功后俄讹,將數(shù)據(jù)加入到磁盤緩存和未解碼的圖片緩存中,然后解碼绕德,返回Bitmap顯示并將其加入到已解碼的圖片緩存中。
簡(jiǎn)單整了個(gè)示意圖摊阀,幫助理解下:
5.2 兼容共享動(dòng)畫
android5.0之后加入了共享動(dòng)畫耻蛇,
相關(guān)的學(xué)習(xí)地址:
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0201/2394.html
http://jcodecraeer.com/a/opensource/2015/0113/2311.html?1422794518
如果直接結(jié)合Fresco和共享動(dòng)畫來(lái)實(shí)現(xiàn)頁(yè)面的過(guò)渡效果,會(huì)發(fā)現(xiàn)無(wú)效或異常胞此。
Fresco官方也給出了說(shuō)明臣咖,https://www.fresco-cn.org/docs/shared-transitions.html
兼容方法:
1.重寫共享動(dòng)畫轉(zhuǎn)換效果的xml文件,注釋掉changeImageTransform漱牵,并將該文件放于res/transition文件夾下
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<explode/>
<changeBounds/>
<changeTransform/>
<changeClipBounds/>
<!--<changeImageTransform/>-->
<!-- Fresco圖片框架不支持changeImageTransform變換夺蛇,
默認(rèn)情況是這五個(gè)變換都使用,所以需要重寫xml并注釋掉changeImageTransform -->
</transitionSet>
2.在style文件中使用上一步重寫的xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="AppTheme.Base">
<!-- 允許使用transitions -->
<item name="android:windowContentTransitions">true</item>
<!-- 指定shared element transitions -->
<item name="android:windowSharedElementEnterTransition">
@transition/share_element_transition</item>
<item name="android:windowSharedElementExitTransition">
@transition/share_element_transition</item>
</style>
</resources>
5.3 瀏覽大圖
“點(diǎn)擊小圖瀏覽大圖酣胀,并且大圖支持縮放刁赦。”
這種需求經(jīng)常能見(jiàn)到闻镶,上面提到的SimpleDraweeView并不支持縮放等功能甚脉,所以需要重新定制一個(gè)控件來(lái)顯示。
官方給出了一個(gè)ZoomableDraweeView來(lái)支持該場(chǎng)景铆农,另外也可以參考PhotoDraweeView
5.4 獲取網(wǎng)絡(luò)請(qǐng)求回來(lái)的Bitmap
有時(shí)候牺氨,我們需要拿到網(wǎng)絡(luò)請(qǐng)求回來(lái)的Bitmap對(duì)象,那么我們可以這么做:
//加載圖片墩剖,在ImageListener回調(diào)里獲取返回的Bitmap
public void getBitmap(Context context, String url, final ImageListener<Bitmap> imageListener) {
//參考自https://github.com/hpdx/fresco-helper/blob/master/fresco-helper/src/main/java/com/facebook/fresco/helper/ImageLoader.java
Uri uri = Uri.parse(url);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
ImageRequest imageRequest = builder.build();
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, context);
dataSource.subscribe(new BaseDataSubscriber<CloseableReference<CloseableImage>>() {
@Override
public void onNewResultImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
if (!dataSource.isFinished()) {
return;
}
CloseableReference<CloseableImage> imageReference = dataSource.getResult();
if (imageReference != null) {
final CloseableReference<CloseableImage> closeableReference = imageReference.clone();
try {
CloseableImage closeableImage = closeableReference.get();
//動(dòng)圖處理
if (closeableImage instanceof CloseableAnimatedImage) {
AnimatedImageResult animatedImageResult = ((CloseableAnimatedImage) closeableImage).getImageResult();
if (animatedImageResult != null && animatedImageResult.getImage() != null) {
int imageWidth = animatedImageResult.getImage().getWidth();
int imageHeight = animatedImageResult.getImage().getHeight();
Bitmap.Config bitmapConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = Bitmap.createBitmap(imageWidth, imageHeight, bitmapConfig);
animatedImageResult.getImage().getFrame(0).renderFrame(imageWidth, imageHeight, bitmap);
if (imageListener != null) {
imageListener.onSuccess(bitmap);
}
}
}
//非動(dòng)圖處理
else if (closeableImage instanceof CloseableBitmap) {
CloseableBitmap closeableBitmap = (CloseableBitmap) closeableImage;
Bitmap bitmap = closeableBitmap.getUnderlyingBitmap();
if (bitmap != null && !bitmap.isRecycled()) {
// https://github.com/facebook/fresco/issues/648
final Bitmap tempBitmap = bitmap.copy(bitmap.getConfig(), false);
if (imageListener != null) {
imageListener.onSuccess(tempBitmap);
}
}
}
} finally {
imageReference.close();
closeableReference.close();
}
}
}
@Override
public void onFailureImpl(DataSource dataSource) {
Throwable throwable = dataSource.getFailureCause();
if (imageListener != null) {
imageListener.onFail(throwable);
}
}
}, UiThreadImmediateExecutorService.getInstance());
}
或者如果緩存里有數(shù)據(jù)猴凹,可以從緩存中取出然后轉(zhuǎn)為bitmap
FileBinaryResource resource = (FileBinaryResource) Fresco.getImagePipelineFactory().getMainFileCache().getResource(new SimpleCacheKey(url));
if (resource != null && resource.getFile() != null) {
Bitmap bitmap = BitmapFactory.decodeFile(resource.getFile().getAbsolutePath());
}
5.5 下載圖片
下載圖片到指定位置,在ImageListener回調(diào)里得到下載結(jié)果
public void downLoadImage(Context context, String url, final File saveFile, final ImageListener<File> imageListener) {
//參考自https://github.com/hpdx/fresco-helper/blob/master/fresco-helper/src/main/java/com/facebook/fresco/helper/ImageLoader.java
Uri uri = Uri.parse(url);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
ImageRequest imageRequest = builder.build();
// 獲取未解碼的圖片數(shù)據(jù)
DataSource<CloseableReference<PooledByteBuffer>> dataSource = imagePipeline.fetchEncodedImage(imageRequest, context);
dataSource.subscribe(new BaseDataSubscriber<CloseableReference<PooledByteBuffer>>() {
@Override
public void onNewResultImpl(DataSource<CloseableReference<PooledByteBuffer>> dataSource) {
if (!dataSource.isFinished()) {
return;
}
CloseableReference<PooledByteBuffer> imageReference = dataSource.getResult();
if (imageReference != null) {
final CloseableReference<PooledByteBuffer> closeableReference = imageReference.clone();
try {
PooledByteBuffer pooledByteBuffer = closeableReference.get();
InputStream inputStream = new PooledByteBufferInputStream(pooledByteBuffer);
OutputStream outputStream = new FileOutputStream(saveFile);
if (FileUtil.saveFile(inputStream, outputStream) && imageListener != null) {
imageListener.onSuccess(saveFile);
}
} catch (Exception e) {
if (imageListener != null) {
imageListener.onFail(e);
}
e.printStackTrace();
} finally {
imageReference.close();
closeableReference.close();
}
}
}
@Override
public void onProgressUpdate(DataSource<CloseableReference<PooledByteBuffer>> dataSource) {
int progress = (int) (dataSource.getProgress() * 100);
RingLog.d("fresco下載圖片進(jìn)度:" + progress);
}
@Override
public void onFailureImpl(DataSource dataSource) {
Throwable throwable = dataSource.getFailureCause();
if (imageListener != null) {
imageListener.onFail(throwable);
}
}
}, Executors.newSingleThreadExecutor());
}
demo中已將前面介紹的配置岭皂、加載圖片的方法等都封裝到FrescoManager類中