您的位置:首页 > 其它

带你了解Fresco

2015-12-03 16:12 316 查看

Fresco用法及简单的介绍

本次主要围绕以下几点讲解:

Fresco是什么

Fresco的重要概念

Fresco的简单使用方法

Fresco ImagePipeline

Part One

Fresco是什么

Fresco是Facebook研发的非常强大的用于图片加载的框架。

Fresco的功能概括起来就2个字,“加载”和“展示”。

Fresco支持从网络和本地加载图片,在加载图片之前,会先展示一个占位符,直到图片被加载出来。

Fresco将Bitmap存放在Ashmem中,不会引发GC,从而导致卡顿。

Fresco支持加载渐进式的JPEG图片和动态的GIF图片,这两项强大的功能是其他的加载库所没有的。

科普:JPEG图片的2种保存方式

1.Baseline JPEG(标准型)和Progressive JPEG(渐进式)

Baseline JPEG保存的图片加载,是从上往下一行一行展示的,而ProgressiveJPEG主要是提现在清晰度上面,先显示图片的模糊轮廓,然后随着扫描次数的增加,越来越清晰。在网络请求中,渐进式的优点就是就算网络不佳的情况下也能通过轮廓大致知道图片是什么。

Part Two

Fresco的重要概念

关键名词的概念:Drawees、DraweeView、DraweeHierarchy、DraweeController、DraweeControllerBuilder、Listeners、Ashmem(Anonymous Shared Memory)、Image Pipeline、ImageRequest。

Drawees:一个比较笼统的说法,其实就是一些组件的合称,Drawees 负责图片的呈现,包含几个组件,有点像MVC模式。

DraweeView:看名字就知道了,它继承自image view,负责展示图片。

使用DraweeView时,请不要使用任何ImageView的属性。因为官方解释后续版本中会

继承View,何属于ImageView但是不属于View的方法都会被移除。

DraweeHierarchy:DraweeHierarchy 用于组织和维护最终绘制和呈现的Drawable对象,相当于MVC中的M。如果你想在Java代码中自定义图片的展示,可以通过这类实现。

比如占位图,动画时间等最终呈现出来的效果都可以在其中设置。

DraweeController:负责和 image loader 交互(即 image pipeline),可以创建一个这个类的实例,来实现对所要显示的图片做更多的控制。比如你想监听加载完成情况就不能简单的通过setUri(url)来加载图片,而需要创建controller对象,然后draweeView中设置该controller对象。

DraweeControllerBuilder:通过build模式创建DraweeController,创建后不可修改

Listeners:我们只需要知道可以监听图片加载完成或失败。

Ashmem:匿名共享内存,不同进程将一段物理内存映射到各自的虚拟内存,从而实现共享。

当你创建一个解码的(未被压缩的)被称为位图的图片,Android的API允许你指明这个图片是可回收的。

[code]    BitmapFactory.Options = new BitmapFactory.Options();
        options.inPurgeable = true;
    Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length,options);


options.inPurgreable:控制 Bitmap 对象是否使用软引用机制, 在系统需要的时候可以回收该对象, 如果在此后, 程序又需要使用该对象, 则系统重新 decode 该对象.

But,垃圾回收器不会自动回收Ashmem中的图片。Android的系统库在系统绘制图片的时候“固定”内存,在图片销毁的时候“取下”内存,这就是所谓的“懒释放”。在任何情况下,内存都可以被系统回收。如果被回收的图片需要再次绘制,系统会在运行时再次解码图片。

SimpleDraweeView 自动处理了该释放过程,所以不是特殊情况,建议使用自带的SimpleDraweeView 。

这里如果想更进一步去了解Ashmem,可以访问:http://blog.chinaunix.net/uid-9185047-id-3318866.html

Image Pipeline:负责图片的获取和管理。图片可以来自远程服务器,本地文件,或者Content Provider,本地资源。压缩后的文件缓存在本地存储中,Bitmap数据缓存在内存中。在5.0系统以下,Image Pipeline 使用`pinned purgeables*将Bitmap数据避开Java堆内存,存在ashmem中。这要求图片不使用时,要显式地释放内存。

SimpleDraweeView 自动处理了这个释放过程,所以没有特殊情况,尽量使用SimpleDraweeView,在特殊的场合,如果有需要,也可以直接控制Image Pipeline。

ImageRequest:存储着Image Pipeline处理被请求图片所需要的有用信息(Uri、是否渐进式图片、是否返回缩略图、缩放、是否自动旋转等。)。

它仅仅用来装信息,而且一经初始化后就无法改变内容(即Immutable,不过可以获取内容)。 并且它的初始化只能通过ImageRequest.fromUri(Uri uri)或ImageRequestBuilder.build()来实现。

SimpleDraweeView调用setUri(Uri)会产生一个默认的ImageRequest含有指定Uri信息,如果需要修改ImageRequest其他信息,必须手动创建ImageRequest,并在PipelineDraweeControllerBuilder调用.build()之前使用.setImageRequest设置它。

Note : Fresco 不支持 相对路径的URI. 所有的URI都必须是绝对路径,并且带上该URI的scheme。

Part Three

Fresco的简单使用方法

XML中这样写:

[code]<com.facebook.drawee.view.SimpleDraweeView
    android:id="@+id/my_image_view"
    android:layout_width="20dp"
    android:layout_height="20dp"
    fresco:fadeDuration="300"
    fresco:actualImageScaleType="focusCrop"
    fresco:placeholderImage="@color/wait_color"
    fresco:placeholderImageScaleType="fitCenter"
    fresco:failureImage="@drawable/error"
    fresco:failureImageScaleType="centerInside"
    fresco:retryImage="@drawable/retrying"
    fresco:retryImageScaleType="centerCrop"
    fresco:progressBarImage="@drawable/progress_bar"
    fresco:progressBarImageScaleType="centerInside"
    fresco:progressBarAutoRotateInterval="1000"
    fresco:backgroundImage="@color/blue"
    fresco:overlayImage="@drawable/watermark"
    fresco:pressedStateOverlayImage="@color/red"
    fresco:roundAsCircle="false"
    fresco:roundedCornerRadius="1dp"
    fresco:roundTopLeft="true"
    fresco:roundTopRight="false"
    fresco:roundBottomLeft="false"
    fresco:roundBottomRight="true"
    fresco:roundWithOverlayColor="@color/corner_color"
    fresco:roundingBorderWidth="2dp"
    fresco:roundingBorderColor="@color/border_color"
  />


注意:drawee不支持wrap_content属性,所以一定要指定宽高

然后代码中

如果只是简单的加载图片:

mSimpleDraweeView.setImageURI(uri);

如果想对显示做些定制,那么就需要用到hierachy了,如下:

[code]List<Drawable> backgroundsList;
List<Drawable> overlaysList;
GenericDraweeHierarchyBuilder builder =
    new GenericDraweeHierarchyBuilder(getResources());
GenericDraweeHierarchy hierarchy = builder
    .setFadeDuration(300)
    .setPlaceholderImage(new MyCustomDrawable())
    .setBackgrounds(backgroundList)
    .setOverlays(overlaysList)
    .build();
mSimpleDraweeView.setHierarchy(hierarchy);


NOTE :

1.对于同一个View,请不要多次调用setHierarchy,即使这个View是可回收的。创建 DraweeHierarchy 的较为耗时的一个过程,应该多次利用

2.hierachy的有些属性是可以运行时候动态改变的。比如以下代码是修改占位图:

[code]//获取view的hierachy的引用
GenericDraweeHierarchy hierarchy = mSimpleDraweeView.getHierachy();
//设置占位图ID
hierarchy.setPlaceholderImage(R.drawable.placeholderId);


接下来讲讲Fresco的亮点:渐进式图片加载和GIF加载

利用Fresco加载渐进式图片

[code]//ProgressiveJpegConfig是一个接口,需要自己实现其中的两个方法。
ProgressiveJpegConfig pjpegConfig = new ProgressiveJpegConfig() {
  @Override
  //下次在该扫描次数时候进行解码,初始为0
  public int getNextScanNumberToDecode(int scanNumber) {
    return scanNumber + 2;
  }    
  //获取当前扫描次数的质量信息
  //这里的意思是,当扫描到第五次的时候就返回该信息
  //ImmutableQualityInfo.of(scanNumber,isGoodEnough,isFullQuality)
  //param1:扫描次数;param2:是否已足够;param3:是否是完整图片质量
  public QualityInfo getQualityInfo(int scanNumber) {
    boolean isGoodEnough = (scanNumber >= 5);
    return ImmutableQualityInfo.of(scanNumber, isGoodEnough, false);
  }
}

ImagePipelineConfig config = ImagePipelineConfig.newBuilder()
    .setProgressiveJpegConfig(pjpegConfig)
    .build();
//最后初始化Fresco
Fresco.initialize(this, config);

//----------------------------注意----------------------------
//虽然上面设置了渐进式加载的配置,但是想要正真实装起来,还需要在请求时候允许渐进式加载
Uri uri = Uri.parse("http://pooyak.com/p/progjpeg/jpegload.cgi?o=1");
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
                .setProgressiveRenderingEnabled(true)//看这里
                .build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
                .setImageRequest(request)
                .build();
mProgressiveJpegView.setController(controller);


利用Fresco加载GIF图片

[code]Uri uri;
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
    . // other setters
    .build();

DraweeController controller = Fresco.newDraweeControllerBuilder()
    .setImageRequest(request)
    .setAutoPlayAnimations(true)//看这里,之需要加上这一行
    . // other setters
    .build();
mSimpleDraweeView.setController(controller);

//----------------GIF另一个有意思的功能-----------------
//如果有动画,Fresco提供了接口访问,然后处理自己的逻辑
Animatable animation = mSimpleDraweeView.getController().getAnimatable();
if (animation != null) {
  // 开始播放
  animation.start();
  // 一段时间之后,根据业务逻辑,停止播放
  animation.stop();
}


Part Four

Fresco ImagePipeline

ImagePipeline是Fresco的一个组件,这里拿出来单独讲,是因为它非常非常之重要,是以后诸位吹牛逼的最大本钱!

那么开始!!

是什么?

Fresco就是通过imagePipeline加载图片的。

下面上图:



上图非常清楚的告诉我们Fresco的加载策略,流程如下:

1.首先UI线程发起请求,然后检查内存缓存,如有,返回bitmap,如果没有,检查本地存储

2.检查本地存储(本地存储的都是未解码过的jpg资源),如有,进行解码然后返回bitmap对象,并将解码后的bitmap对象放入内存缓存中;如果本地存储中没有,那么从网络下载

3.从网络下载资源,下载好的资源存入本地存储,同时进解码,然后返回。

注意:每次解码后都会将解码后的bitmap存入内存缓存中,如果从网络下载了资源,先存入本地存储。

下面是使用:

[code]//这里是所有的配置,根据实际需求进行配置
//比如下面的渐进式图片加载,具体配置作用,自行查询
ImagePipelineConfig config = ImagePipelineConfig.newBuilder()
    .setBitmapMemoryCacheParamsSupplier(bitmapCacheParamsSupplier)
    .setCacheKeyFactory(cacheKeyFactory)
    .setEncodedMemoryCacheParamsSupplier(encodedCacheParamsSupplier)
    .setExecutorSupplier(executorSupplier)
    .setImageCacheStatsTracker(imageCacheStatsTracker)
    .setMainDiskCacheConfig(mainDiskCacheConfig)
    .setMemoryTrimmableRegistry(memoryTrimmableRegistry) 
    .setNetworkFetchProducer(networkFetchProducer)
    .setPoolFactory(poolFactory)
    .setProgressiveJpegConfig(progressiveJpegConfig)
    .setRequestListeners(requestListeners)
    .setSmallImageDiskCacheConfig(smallImageDiskCacheConfig)
    .build();
//初始化的时候传入你写好的配置    
Fresco.initialize(context, config);


==============妖娆的分割线=============

好了,Fresco的基本介绍到此为止,更为深入的内容大家自行探索。

以后后续遇到Fresco的问题,如果值得分享,会进行更新。

附上github上的地址:

https://github.com/facebook/fresco
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: