转载自:http://blog.csdn.net/ljy_programmer/article/details/78273267

学习/参考地址: 
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是一个出自Facebook的功能强大的图片加载库

优点: 
1)内存自动回收。图片不可见时,会及时自动释放所占用的内存,尽可能地避免OOM 
2)三级缓存机制。两级内存缓存(解码的与未解码的)+一级磁盘缓存,提示加载速度,节省内存占用空间 
3)支持各种加载场景。如动图加载、高斯模糊、渐进式加载、先加载小图再加载大图,以及其它常见的图片加载场景

缺点: 
1)体积较大。较其他主流图片库体积要大一些 
2)侵入性较强。须使用它提供的SimpleDraweeView来代替ImageView加载显示图片

综合来说肯定是利大大大于弊,尤其是当你的应用需要加载很多图片时,更能凸显其价值。


介绍

下面通过 配置、SimpleDraweeView、加载图片、混淆、其他 这几个部分来介绍。

1. 配置

1.1 添加依赖

compile 'com.facebook.fresco:fresco:1.5.0'
compile 'com.facebook.fresco:animated-gif:1.5.0'//加载gif动图需添加此库
compile 'com.facebook.fresco:animated-webp:1.5.0'//加载webp动图需添加此库
compile 'com.facebook.fresco:webpsupport:1.5.0'//支持webp需添加此库
compile 'com.facebook.fresco:imagepipeline-okhttp3:1.5.0'//网络实现层使用okhttp3需添加此库
  • 1
  • 2
  • 3
  • 4
  • 5

1.2 设置磁盘缓存

ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setMainDiskCacheConfig(DiskCacheConfig.newBuilder(context)
.setBaseDirectoryPath(context.getExternalCacheDir())//设置磁盘缓存的路径
.setBaseDirectoryName(BaseConstants.APP_IMAGE)//设置磁盘缓存文件夹的名称
.setMaxCacheSize(MAX_DISK_CACHE_SIZE)//设置磁盘缓存的大小
.build());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

1.3 设置内存缓存

设置已解码的内存缓存(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;//取手机内存最大值的五分之一作为可用的最大内存数MemoryCacheParams bitmapCacheParams = new MemoryCacheParams( //// 可用最大内存数,以字节为单位MAX_MEMORY_CACHE_SIZE,// 内存中允许的最多图片数量Integer.MAX_VALUE,// 内存中准备清理但是尚未删除的总图片所可用的最大内存数,以字节为单位MAX_MEMORY_CACHE_SIZE,// 内存中准备清除的图片最大数量Integer.MAX_VALUE,// 内存中单图片的最大大小Integer.MAX_VALUE);return bitmapCacheParams;}});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

设置未解码的内存缓存

ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setEncodedMemoryCacheParamsSupplier(new Supplier<MemoryCacheParams>() {public MemoryCacheParams get() {MemoryCacheParams bitmapCacheParams;//设置大小,可参考上面已解码的内存缓存return bitmapCacheParams;}});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

1.4 设置内存紧张时的应对措施

MemoryTrimmableRegistry memoryTrimmableRegistry = NoOpMemoryTrimmableRegistry.getInstance();
memoryTrimmableRegistry.registerMemoryTrimmable(new MemoryTrimmable() {@Overridepublic void trim(MemoryTrimType trimType) {final double suggestedTrimRatio = trimType.getSuggestedTrimRatio();if (MemoryTrimType.OnCloseToDalvikHeapLimit.getSuggestedTrimRatio() == suggestedTrimRatio || MemoryTrimType.OnSystemLowMemoryWhileAppInBackground.getSuggestedTrimRatio() == suggestedTrimRatio || MemoryTrimType.OnSystemLowMemoryWhileAppInForeground.getSuggestedTrimRatio() == suggestedTrimRatio) { //清空内存缓存ImagePipelineFactory.getInstance().getImagePipeline().clearMemoryCaches();}}});ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setMemoryTrimmableRegistry(memoryTrimmableRegistry);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

1.5 设置渐进式显示的效果

ProgressiveJpegConfig progressiveJpegConfig = new ProgressiveJpegConfig() {@Overridepublic int getNextScanNumberToDecode(int scanNumber) {//返回下一个需要解码的扫描次数return scanNumber + 2;}    public QualityInfo getQualityInfo(int scanNumber) {boolean isGoodEnough = (scanNumber >= 5);//确定多少个扫描次数之后的图片才能开始显示。return ImmutableQualityInfo.of(scanNumber, isGoodEnough, false);}
};
//具体含义可参考 http://wiki.jikexueyuan.com/project/fresco/progressive-jpegs.htmlImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setProgressiveJpegConfig(progressiveJpegConfig);
//或者使用默认的效果
//imagePipelineConfigBuilder.setProgressiveJpegConfig(new SimpleProgressiveJpegConfig());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

设置完效果后,还需在下面介绍的ImageRequest中开启渐进式加载。

1.6 允许解码时调整图片大小

允许后,即可在后面介绍的ImageRequest中对结合ResizeOptions对解码后的图片大小进行调整,从而优化了图片所占大小。默认只支持JPEG图,所以要设置该属性来支持png、jpg、webp。

ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setDownsampleEnabled(true);
  • 1
  • 2

1.7 开启Log

FLog.setMinimumLoggingLevel(FLog.VERBOSE);
Set<RequestListener> requestListeners = new HashSet<>();
requestListeners.add(new RequestLoggingListener());ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setRequestListeners(requestListeners);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

1.8 初始化

上面的各种配置都是通过ImagePipelineConfig进行的,接着需要进行初始化,在Application中初始化即可

ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);//...进行各种设置ImagePipelineConfig config = imagePipelineConfigBuilder.build();
Fresco.initialize(context, config);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果想直接使用默认的配置,可以

Fresco.initialize(context);
  • 1

2. SimpleDraweeView

Fresco要求使用SimpleDraweeView来替换ImageView进行图片的加载与显示,不少人也是因为这一点而不想使用Fresco。 
下面介绍SimpleDraweeView在xml中的各种属性

//在最外层布局的属性中加入xmlns:fresco="http://schemas.android.com/apk/res-auto"<com.facebook.drawee.view.SimpleDraweeViewandroid: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"/>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

上面各个属性的作用说明:(来自http://www.jianshu.com/p/8ff81be83101)

属性 作用说明
actualImageScaleType 加载完成的图片的缩放样式
fadeDuration 由进度条和占位符图片渐变过渡到加载完成的图片所使用的时间间隔
failureImage 加载失败所使用的图片
failureImageScaleType 加载失败所使用的图片的缩放样式
placeholderImage 占位符图片
placeholderImageScaleType 占位符图片的缩放样式
progressBarAutoRotateInterval 旋转进度条旋转1圈所需要的时间
progressBarImage 旋转进度条所使用的图片
progressBarImageScaleType 旋转进度条所使用的图片的缩放样式
retryImage 重试所使用的图片
retryImageScaleType 重试所使用的图片的缩放样式
backgroundImage 背景图片
overlayImage 覆盖在加载完成后图片上的叠加图片
pressedStateOverlayImage 按压状态下的叠加图片
roundAsCircle 是否将图片剪切为圆形
roundedCornerRadius 圆角图片时候,圆角的半径大小
roundTopLeft 左上角是否为圆角
roundTopRight 右上角是否为圆角
roundBottomLeft 左下角是否为圆角
roundBottomRight 右下角是否为圆角
roundWithOverlayColor 圆角或圆形图叠加的颜色,只能是颜色
roundingBorderWidth 圆角或圆形图边框的宽度
roundingBorderColor 圆角或圆形图边框的颜色
viewAspectRatio 设置宽高比

各个属性的效果图,可到http://blog.csdn.net/wyb112233/article/details/49637685查看,我就不重复造轮子了。 
*注意: 
1)android:src属性对于SimpleDraweeView无效,必要的话可用fresco:placeholderImage来设置。 
2)SimpleDraweeView不支持android:layout_width和android:layout_height同时都设为wrap_content。

3. 加载图片

使用Fresco加载图片,大致是按以下流程进行的。 
1. 设置Hierarchay(上面xml中的属性,可在这进行设置) 
2. 构建ImageRequest(加载路径、开启渐进式加载、高斯模糊、调整解码图片大小等,可在这进行设置) 
3. 构建DraweeController(动图加载、失败后点击重新加载等,可在这进行设置) 
4. 进行图片加载

3.1 设置Hierarchay

虽然xml中的属性都能在这一步通过代码进行设置,但一般只在这设置一些统一固定的属性,比如加载占位图、加载失败图等。

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);//对Hierarchy进行设置,如各种状态下显示的图片
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);//设置加载成功后图片的缩放模式hierarchy.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP);//其他设置请查看具体API。}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

3.2 构建ImageRequest

/*** 构建、获取ImageRequest* @param uri 加载路径* @param progressiveRenderingEnabled 是否开启渐进式加载* @param blurEnable 是否开启高斯模糊* @param simpleDraweeView 加载的图片控件* @return ImageRequest*/
public ImageRequest getImageRequest(Uri uri, boolean progressiveRenderingEnabled, boolean blurEnable, 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();}//根据请求路径生成ImageRequest的构造者ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);//调整解码图片的大小if (width > 0 && height > 0) {builder.setResizeOptions(new ResizeOptions(width, height));}//是否开启渐进式加载,仅支持JPEG图片builder.setProgressiveRenderingEnabled(progressiveRenderingEnabled);//是否开启高斯模糊效果if (blurEnable) {builder.setPostprocessor(new BasePostprocessor() {@Overridepublic String getName() {return "blurPostprocessor";}@Overridepublic void process(Bitmap bitmap) {//第二个参数值控制模糊程度,越大越模糊BitmapBlurHelper.blur(bitmap, 15);}});}return builder.build();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

3.3 构建DraweeController

/**
* 构建、获取Controller
* @param request
* @param oldController
* @return
*/
public DraweeController getController(ImageRequest request, @Nullable DraweeController oldController) {PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder();builder.setImageRequest(request);//设置图片请求builder.setTapToRetryEnabled(false);//设置是否允许加载失败时点击再次加载builder.setAutoPlayAnimations(true);//设置是否允许动画图自动播放builder.setOldController(oldController);return builder.build();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3.4 进行图片加载

创建一个loadImage方法将上面的Hierarchy、ImageRequest、DraweeController串在一起,供具体的加载场景使用

/**
* 加载图片核心方法
*
* @param simpleDraweeView              图片加载控件
* @param uri                           图片加载地址
* @param progressiveRenderingEnabled   是否开启渐进式加载
* @param blurEnable                    是否开启高斯模糊效果
*/
public void loadImage(SimpleDraweeView simpleDraweeView, Uri uri, boolean progressiveRenderingEnabled, boolean blurEnable) {//设置HierarchysetHierarchay(simpleDraweeView.getHierarchy());//构建并获取ImageRequestImageRequest imageRequest = getImageRequest(uri, progressiveRenderingEnabled, blurEnable, simpleDraweeView);//构建并获取ControllerDraweeController draweeController = getController(imageRequest, simpleDraweeView.getController());//开始加载simpleDraweeView.setController(draweeController);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

具体的加载场景: 
- 加载网络图片,包括gif/webp动图

 public void loadNetImage(SimpleDraweeView simpleDraweeView, String url) {Uri uri = Uri.parse(url);loadImage(simpleDraweeView, uri, false, false);}
  • 1
  • 2
  • 3
  • 4
  • 加载本地文件图片
public void loadLocalImage(SimpleDraweeView simpleDraweeView, String fileName) {Uri uri = Uri.parse("file://" + fileName);loadImage(simpleDraweeView, uri, false, false);
}
  • 1
  • 2
  • 3
  • 4
  • 加载res下资源图片
public void loadResourceImage(SimpleDraweeView simpleDraweeView, @DrawableRes int resId) {Uri uri = Uri.parse("res:///" + resId);loadImage(simpleDraweeView, uri, false, false);
}
  • 1
  • 2
  • 3
  • 4
  • 加载ContentProvider下的图片
public void loadContentProviderImage(SimpleDraweeView simpleDraweeView, int resId) {Uri uri = Uri.parse("content:///" + resId);loadImage(simpleDraweeView, uri, false, false);
}
  • 1
  • 2
  • 3
  • 4
  • 加载asset下的图片
public void loadAssetImage(SimpleDraweeView simpleDraweeView, int resId) {Uri uri = Uri.parse("asset:///" + resId);loadImage(simpleDraweeView, uri, false, false);
}
  • 1
  • 2
  • 3
  • 4
  • 加载网络图片,先加载小图,待大图加载完成后再替换掉小图

这个需要修改一下DraweeController的构建,通过setLowResImageRequest来添加小图请求

public DraweeController getSmallToBigController(ImageRequest smallRequest, ImageRequest bigRequest, @Nullable DraweeController oldController) {PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder();builder.setLowResImageRequest(smallRequest);//小图的图片请求builder.setImageRequest(bigRequest);//大图的图片请求builder.setTapToRetryEnabled(false);//设置是否允许加载失败时点击再次加载builder.setAutoPlayAnimations(true);//设置是否允许动画图自动播放builder.setOldController(oldController);return builder.build();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
public void loadImageSmallToBig(SimpleDraweeView simpleDraweeView, Uri smallUri, Uri bigUri) {//设置HierarchysetHierarchay(simpleDraweeView.getHierarchy());//构建小图的图片请求ImageRequest smallRequest = getImageRequest(smallUri, false, false, simpleDraweeView);//构建大图的图片请求ImageRequest bigRequest = getImageRequest(bigUri, false, false, simpleDraweeView);//构建ControllerDraweeController draweeController = getSmallToBigController(smallRequest, bigRequest, simpleDraweeView.getController());//开始加载simpleDraweeView.setController(draweeController);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
//加载网络图片,先加载小图,待大图加载完成后替换
public void loadNetImageSmallToBig(SimpleDraweeView simpleDraweeView, String smallUrl, String bigUrl) {Uri smallUri = Uri.parse(smallUrl);Uri bigUri = Uri.parse(bigUrl);loadImageSmallToBig(simpleDraweeView, smallUri, bigUri);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4. 混淆

在proguard-rules.pro文件中添加以下内容进行混淆配置

#fresco开始
-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结束
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

5. 其他

5.1 缓存策略

Fresco采用三级缓存机制,两级内存缓存+一级磁盘缓存,其中两级内存缓存分为已解码的图片缓存(Bitmap缓存)和未解码的图片缓存。 
下面通过加载流程来了解其缓存策略。 
1. 根据Uri到已解码的图片缓存中查找是否存在对应的Bitmap。如果存在,则返回Bitmap显示; 
如果不存在,则到未解码的图片缓存中查找。 
2. 如果在未解码的图片缓存中存在对应的数据,则解码,返回Bitmap显示并将其加入到已解码的图片缓存中;如果不存在,则到磁盘缓存中查找。 
3. 如果在磁盘缓存中存在对应的数据,则将数据加入到未解码的图片缓存中,然后解码,返回Bitmap显示并将其加入到已解码的图片缓存中;如果不存在,则进行网络请求或者到本地文件加载。 
4. 请求或加载成功后,将数据加入到磁盘缓存和未解码的图片缓存中,然后解码,返回Bitmap显示并将其加入到已解码的图片缓存中。

简单整了个示意图,帮助理解下: 

5.2 兼容共享动画

android5.0之后加入了共享动画, 
相关的学习地址: 
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0201/2394.html 
http://jcodecraeer.com/a/opensource/2015/0113/2311.html?1422794518

如果直接结合Fresco和共享动画来实现页面的过渡效果,会发现无效或异常。 
Fresco官方也给出了说明,https://www.fresco-cn.org/docs/shared-transitions.html

兼容方法: 
1.重写共享动画转换效果的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变换,默认情况是这五个变换都使用,所以需要重写xml并注释掉changeImageTransform -->
</transitionSet>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

5.3 浏览大图

“点击小图浏览大图,并且大图支持缩放。” 
这种需求经常能见到,上面提到的SimpleDraweeView并不支持缩放等功能,所以需要重新定制一个控件来显示。 
官方给出了一个ZoomableDraweeView来支持该场景,另外也可以参考PhotoDraweeView

5.4 获取网络请求回来的Bitmap

有时候,我们需要拿到网络请求回来的Bitmap对象,那么我们可以这么做:

//加载图片,在FrescoBitmapCallback里获取返回的Bitmap
public final void loadImageBitmap(String url, FrescoBitmapCallback<Bitmap> callback) {if (TextUtils.isEmpty(url)) {return;}try {fetch(Uri.parse(url), callback);} catch (Exception e) {//oom风险.e.printStackTrace();callback.onFailure(Uri.parse(url), e);}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
private void fetch(final Uri uri, final FrescoBitmapCallback<Bitmap> callback) throws Exception {ImageRequestBuilder requestBuilder = ImageRequestBuilder.newBuilderWithSource(uri);ImageRequest imageRequest = requestBuilder.build();DataSource<CloseableReference<CloseableImage>> dataSource = ImagePipelineFactory.getInstance().getImagePipeline().fetchDecodedImage(imageRequest, null);dataSource.subscribe(new BaseBitmapDataSubscriber() {@Overridepublic void onNewResultImpl(@Nullable final Bitmap bitmap) {if (callback == null) return;if (bitmap != null && !bitmap.isRecycled()) {//后台线程中加载Executors.newSingleThreadExecutor().submit(new Callable<Bitmap>() {@Overridepublic Bitmap call() throws Exception {final Bitmap resultBitmap = bitmap.copy(bitmap.getConfig(), bitmap.isMutable());if (resultBitmap != null && !resultBitmap.isRecycled()) {//回调UI线程中去new Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() {callback.onSuccess(uri, resultBitmap);}});}return resultBitmap;}});}}@Overridepublic void onCancellation(DataSource<CloseableReference<CloseableImage>> dataSource) {super.onCancellation(dataSource);if (callback == null) return;callback.onCancel(uri);}@Overridepublic void onFailureImpl(DataSource dataSource) {if (callback == null) return;Throwable throwable = null;if (dataSource != null) {throwable = dataSource.getFailureCause();}callback.onFailure(uri, throwable);}}, UiThreadImmediateExecutorService.getInstance());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
public interface FrescoBitmapCallback<T> {void onSuccess(Uri uri, T result);void onFailure(Uri uri, Throwable throwable);void onCancel(Uri uri);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

使用

demo中已将前面介绍的配置、加载图片的方法等都封装到FrescoUtil类中。大家可以根据自己的需求到FrescoUitl中进行修改定制。 
1.在Application中初始化

//初始化Fresco
FrescoUtil.getInstance().initializeFresco(this);
  • 1
  • 2

2.在需要加载图片的地方调用相关方法

//加载网络图片
FrescoUtil.getInstance().loadNetImage(simpleDraweeView, imageUrl);
//加载res下的图片
FrescoUtil.getInstance().loadResourceImage(simpleDraweeView, resId);
....
  • 1
  • 2
  • 3
  • 4
  • 5

详细代码请看demo,地址:https://github.com/LJYcoder/DevBase 
demo的内容流程,请看《安卓开发框架(MVP+主流框架+基类+工具类)— 开篇》

安卓开发框架(MVP+主流框架+基类+工具类)--- Fresco相关推荐

  1. 解密android日志xlog,安卓开发技巧2:自定义日志工具类XLog的实现

    安卓开发技巧二:自定义日志工具类XLog的实现 我们在开发过程中,打印日志是必不可少的一个调试环节,然而,直接使用系统自带的Log日志类,并不能满足我们实际项目的需求:假如我们现在在开发一款比较大的项 ...

  2. 后端常用数据持久层模板及框架以及一些工具类模板的配置使用集合

    文章目录 后端常用数据持久层模板及框架以及一些工具类模板的配置使用集合 JDBC.c3p0.hibernate配置模板:JDBC模板方法模式.抽象工厂模式封装模板:Spring+hibernate+c ...

  3. Java集成ElasticSearch及配置类工具类整理

    Java集成ElasticSearch及配置类工具类整理 前言:做一个有梦想的程序猿! ES不同的版本API差异比较大,此处ES版本为:6.5.3 代码如下: 添加Maven依赖 <!-- ES ...

  4. 开发自己的框架——(二)数据库工具类的封装

    为了让框架的内容与数据分离,我们把常用的类封装到一个工具类中,当用到这些方法时,就调用这个封装好的类,能够使代码的复用性得到很大的提高. 首先,封装数据库相关操作,为了使封装规范化,我们创建一个接口让 ...

  5. Java集合框架:Collections工具类

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  6. Java集合框架:Arrays工具类

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  7. java发送iso8583报文接口框架,ISO8583报文工具类(组装和解析报文)

    package com.lsy.common.util; import java.io.FileInputStream; import java.io.UnsupportedEncodingExcep ...

  8. android gps定位工具类,工具类之LocationUtils(定位工具类)

    无须引入第三方定位,单纯依赖v4包,如果只是需要简单的定位,那么这份工具类可以很好地帮助到你,老司机不多说,辛酸的话语都留在了代码里了,上效果演示 LocationDemo Demo牛逼地显示是当时查 ...

  9. android 经纬度工具类,工具类之LocationUtils(定位工具类)

    无须引入第三方定位,单纯依赖v4包,如果只是需要简单的定位,那么这份工具类可以很好地帮助到你,老司机不多说,辛酸的话语都留在了代码里了,上效果演示 LocationDemo Demo牛逼地显示是当时查 ...

最新文章

  1. 湖南大学超级计算机中心 舒教授,湖南大学岳麓书院哲学系舒远招教授应邀来我院讲学...
  2. linux获取明文密码,linux下抓取内存中明文密码mimipenguin
  3. .NET中的异步编程(四)- IO完成端口以及FileStream.BeginRead
  4. 强化学习笔记4:强化学习分类
  5. codeproject上的一款分页控件
  6. phpfpm怎么连接mysql_php-fpm连不上mysql的问题?
  7. android 全局dp单位,android应用开发之View的大小计量单位(px、dpi、dp、dip、sp)
  8. NLP知识包--语义分析-语义角色标注
  9. python是什么意思-python中class是什么意思
  10. java 线程不安全例子_Java中多线程安全问题实例分析
  11. 你和高级工程师的差距在哪里?
  12. 经纬度距离计算小工具_一个NB工具大合集打网站,总有一款是你需要的
  13. ENVI大气校正后遥感图像颜色变了及编辑头文件
  14. Beetlsql自学笔记
  15. 建筑企业并购:人才整合的三大误区
  16. Pathon 连接数据库
  17. python csv 大文件_python 快速把超大txt文件转存为csv的实例
  18. 【MySQL】联结表
  19. 【微电网优化】基于matlab粒子群算法求解综合能源系统优化问题【含Matlab源码 1969期】
  20. “鸡”不可失,驱动人生助力开启“绝地求生”

热门文章

  1. Linux的NTP深度学习
  2. SFP GBIC XFP SFP+光模块的区别杂谈
  3. 计算机模拟数学建模,数学建模--计算机模拟.ppt
  4. 计算机反复启动开不了机,电脑反复启动开不了机
  5. OrangePI使用 Rust-python 完整教程
  6. 智能充电桩系统PHP源码,【基于51单片机】电动车智能充电桩(全套)
  7. 1508-张晨曦总结《2016年-10月-31日》【连续10天总结】
  8. oracle数据库应用与实践课件,Oracle数据库管理、开发与实践 教学课件 作者 杨永健 刘尚毅 第6章 PL SQL编程.ppt...
  9. adobexd怎么录屏_了解如何使用 Adobe XD 预览原型和录制交互。 - Adobe XD 用户指南...
  10. Android SurfaceView实战 带你玩转flabby bird