美文网首页Android 程序开发Android开发程序员
Android图片加载神器之Fresco,基于各种使用场景的讲解

Android图片加载神器之Fresco,基于各种使用场景的讲解

作者: android_ls | 来源:发表于2016-11-16 09:55 被阅读1128次

    Fresco是Facebook开源Android平台上一个强大的图片加载库,也是迄今为止Android平台上最强大的图片加载库。

    优点:相对于其他开源的第三方图片加载库,Fresco拥有更好的内存管理和强大的功能,基本上能满足所有的日常使用场景。

    缺点:整体比较大,不过目前的版本已做了拆分,你只需要导入你使用到的功能相关的库。从代码层面来说侵入性太强,体现在要使用它需要用Fresco的组件SimpleDraweeView替换掉Android原生图片显示组件ImageView,这也是很多人不愿意在项目中接入Fresco的主要原因。

    特性:
    1、内存管理
    解压后的图片,即Android中的Bitmap,占用大量的内存。大的内存占用势必引发更加频繁的GC。在5.0以下,GC将会显著地引发界面卡顿。
    在5.0以下系统,Fresco将图片放到一个特别的内存区域。当然,在图片不显示的时候,占用的内存会自动被释放。这会使得APP更加流畅,减少因图片内存占用而引发的OOM。

    2、Image Pipeline
    Fresco中设计有一个叫做 Image Pipeline 的模块。它负责从网络,从本地文件系统,本地资源加载图片和管理。为了最大限度节省空间和CPU时间,它含有3级缓存设计(2级内存,1级磁盘)。两个内存缓存为Bitmap缓存和未解码的图片缓存,这样既可以加快图片的加载速度,又能节省内存的占用(解码后的图片就是Bitmap,其占用内存相对未解码的图片数据而言会大很多)。
    Image pipeline 负责完成加载图像,变成Android设备可呈现的形式所要经历的大致流程如下:
    a、根据Uri在已解码的(Bitmap缓存)内存缓存中查找,找到了则返回Bitmap对象;如果没找到,则开启后台线程开始后续的工作。
    b、根据Uri在未解码的内存缓存中查找,若找到了则解码,然后缓存到已解码的内存缓存中,并且返回Bitmap对象。
    d、如果在未解码的内存缓存中没找到,则根据Uri在磁盘缓存中查找,若找到了则读取数据(byte数组),并缓存到未解码的内存缓存中,解码、然后缓存到已解码的内存缓存中,并且返回Bitmap对象。
    e、如果在磁盘缓存中没找到,则从网络或者本地加载数据。加载完成后,依次缓存到磁盘缓存未解码的内存缓存中。解码、然后缓存到已解码的内存缓存中,并且返回Bitmap对象。

    其流程图如下:


    这里写图片描述

    3、Drawees
    Fresco 中设计有一个叫做 Drawees 模块,负责图片的呈现。它由三个元素组成分别是:
    DraweeView 继承于 View, 负责图片的显示。
    DraweeHierarchy 用于组织和维护最终绘制和呈现的 Drawable 对象。
    DraweeController 负责和ImagePipeline的交互,可以创建一个这个类的实例,来实现对所要显示的图片做更多的控制。
    一般情况下,使用 SimpleDraweeView 即可,你可以配置其XML属性来实现各式各样的展示效果。
    a、在图片加载完成前显示占位图;
    b、在图片加载的过程中显示加载进度图;
    c、加载成功后,将占位图或者加载进度图,自动替换为目标图片。
    d、加载失败后,它会显示加载失败的图(若没配置加载失败的图,则显示的是占位图)
    e、加载失败后,若配置过重试图,则会显示重试图,用户点击可以重新去加载图片(默认配置可重试3次)
    f、自定义居中焦点(配合Google提供的服务可以实现人脸识别,经测试国内目前使用不了)
    g、显示圆角图、圆形图和圆圈;
    h、添加覆盖物(图层叠加);
    j、 实现图片的按下效果;
    k、图片的渐进式呈现;(目前只支持Jpeg格式的图片)
    x、当图片不再显示在屏幕上时,它会及时地释放内存和空间占用。

    4、Fresco目前所支持的图片格式
    a、静态图:png、jpg、web
    b、动态图:gif、web格式的gif

    以上聊了这么多,大概意思就是Fresco出身名门,很好很强大,超牛逼!接下来我们来聊聊在项目中的具体使用。我专门写了一个针对Fresco的使用帮助库,先给大家看看Demo的运行效果图:


    常见的各种效果


    从网络加载的图片墙


    点击图片墙中的照片后,打开的浏览大图界面


    一、Fresco的引入及ImagePipeline参数配置
    1、在build.gradle文件中添加依赖

    dependencies {
        // ......
    
        compile 'com.facebook.fresco:fresco:0.14.1'
        compile 'com.facebook.fresco:animated-base-support:0.14.1'
        compile 'com.facebook.fresco:animated-gif:0.14.1'
        compile 'com.facebook.fresco:webpsupport:0.14.1'
        compile 'com.facebook.fresco:animated-webp:0.14.1'
        compile 'com.facebook.fresco:imagepipeline-okhttp3:0.14.1'
    }
    

    a、在 API < 14 上的机器支持 WebP 时,需要添加以下依赖

    compile 'com.facebook.fresco:animated-base-support:0.14.1'
    

    b、支持GIF动图,需要添加以下依赖

     compile 'com.facebook.fresco:animated-gif:0.14.1'
    

    c、支持WebP,需要添加以下依赖

    compile 'com.facebook.fresco:webpsupport:0.14.1'
    

    d、支持WebP动图,需要添加以下依赖

     compile 'com.facebook.fresco:animated-webp:0.14.1'
    

    e、网络实现层想使用okhttp3,需要添加以下依赖

    compile 'com.facebook.fresco:imagepipeline-okhttp3:0.14.1'
    

    2、ImagePipeline配置
    a、磁盘缓存目录,推荐缓存到应用本身的缓存文件夹,这么做的好处是:当应用被用户卸载后能自动清除缓存,增加用户好感(可能以后用得着时,还会想起我);一些内存清理软件可以扫描出来,进行内存的清理。

    File fileCacheDir = context.getApplicationContext().getCacheDir();
    

    b、配置磁盘缓存,大部分的应用有一个磁盘缓存就够了,但是在一些情况下,你可能需要两个缓存。比如你想把小文件放在一个缓存中(50*50及以下尺寸),大文件放在另外一个文件中,这样小文件就不会因大文件的频繁变动而被从缓存中移除。

     DiskCacheConfig mainDiskCacheConfig = DiskCacheConfig.newBuilder(context)
                        .setBaseDirectoryName(IMAGE_PIPELINE_CACHE_DIR)
                        .setBaseDirectoryPath(fileCacheDir)
                        .build();
    
                DiskCacheConfig smallDiskCacheConfig = DiskCacheConfig.newBuilder(context)
                        .setBaseDirectoryPath(fileCacheDir)
                        .setBaseDirectoryName(IMAGE_PIPELINE_SMALL_CACHE_DIR)
                        .setMaxCacheSize(MAX_DISK_SMALL_CACHE_SIZE)
                        .setMaxCacheSizeOnLowDiskSpace(MAX_DISK_SMALL_ONLOWDISKSPACE_CACHE_SIZE)
                        .build();
    

    c、ImagePipeline的完整配置代码如下:

    package com.facebook.fresco.helper.config;
    
    import android.app.ActivityManager;
    import android.content.Context;
    import android.graphics.Bitmap;
    
    import com.facebook.cache.disk.DiskCacheConfig;
    import com.facebook.common.logging.FLog;
    import com.facebook.common.memory.MemoryTrimType;
    import com.facebook.common.memory.MemoryTrimmable;
    import com.facebook.common.memory.MemoryTrimmableRegistry;
    import com.facebook.common.memory.NoOpMemoryTrimmableRegistry;
    import com.facebook.common.util.ByteConstants;
    import com.facebook.drawee.backends.pipeline.Fresco;
    import com.facebook.fresco.helper.utils.MLog;
    import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory;
    import com.facebook.imagepipeline.core.ImagePipelineConfig;
    import com.facebook.imagepipeline.decoder.ProgressiveJpegConfig;
    import com.facebook.imagepipeline.image.ImmutableQualityInfo;
    import com.facebook.imagepipeline.image.QualityInfo;
    import com.facebook.imagepipeline.listener.RequestListener;
    import com.facebook.imagepipeline.listener.RequestLoggingListener;
    
    import java.io.File;
    import java.util.HashSet;
    import java.util.Set;
    
    import okhttp3.OkHttpClient;
    import okhttp3.logging.HttpLoggingInterceptor;
    
    /**
     *
     * Created by android_ls on 16/9/8.
     */
    public class ImageLoaderConfig {
    
        private static final String IMAGE_PIPELINE_CACHE_DIR = "image_cache";
    
        private static final String IMAGE_PIPELINE_SMALL_CACHE_DIR = "image_small_cache";
    
        private static final int MAX_DISK_SMALL_CACHE_SIZE = 10 * ByteConstants.MB;
    
        private static final int MAX_DISK_SMALL_ONLOWDISKSPACE_CACHE_SIZE = 5 * ByteConstants.MB;
    
        private static ImagePipelineConfig sImagePipelineConfig;
    
        /**
         * Creates config using android http stack as network backend.
         */
        public static ImagePipelineConfig getImagePipelineConfig(final Context context) {
            if (sImagePipelineConfig == null) {
                /**
                 * 推荐缓存到应用本身的缓存文件夹,这么做的好处是:
                 * 1、当应用被用户卸载后能自动清除缓存,增加用户好感(可能以后用得着时,还会想起我)
                 * 2、一些内存清理软件可以扫描出来,进行内存的清理
                 */
                File fileCacheDir = context.getApplicationContext().getCacheDir();
    //            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
    //                fileCacheDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Fresco");
    //            }
    
                DiskCacheConfig mainDiskCacheConfig = DiskCacheConfig.newBuilder(context)
                        .setBaseDirectoryName(IMAGE_PIPELINE_CACHE_DIR)
                        .setBaseDirectoryPath(fileCacheDir)
                        .build();
    
                DiskCacheConfig smallDiskCacheConfig = DiskCacheConfig.newBuilder(context)
                        .setBaseDirectoryPath(fileCacheDir)
                        .setBaseDirectoryName(IMAGE_PIPELINE_SMALL_CACHE_DIR)
                        .setMaxCacheSize(MAX_DISK_SMALL_CACHE_SIZE)
                        .setMaxCacheSizeOnLowDiskSpace(MAX_DISK_SMALL_ONLOWDISKSPACE_CACHE_SIZE)
                        .build();
    
                FLog.setMinimumLoggingLevel(FLog.VERBOSE);
                Set<RequestListener> requestListeners = new HashSet<>();
                requestListeners.add(new RequestLoggingListener());
    
                // 当内存紧张时采取的措施
                MemoryTrimmableRegistry memoryTrimmableRegistry = NoOpMemoryTrimmableRegistry.getInstance();
                memoryTrimmableRegistry.registerMemoryTrimmable(new MemoryTrimmable() {
                    @Override
                    public void trim(MemoryTrimType trimType) {
                        final double suggestedTrimRatio = trimType.getSuggestedTrimRatio();
                        MLog.i(String.format("Fresco onCreate suggestedTrimRatio : %d", suggestedTrimRatio));
    
                        if (MemoryTrimType.OnCloseToDalvikHeapLimit.getSuggestedTrimRatio() == suggestedTrimRatio
                                || MemoryTrimType.OnSystemLowMemoryWhileAppInBackground.getSuggestedTrimRatio() == suggestedTrimRatio
                                || MemoryTrimType.OnSystemLowMemoryWhileAppInForeground.getSuggestedTrimRatio() == suggestedTrimRatio
                                ) {
                            // 清除内存缓存
                            Fresco.getImagePipeline().clearMemoryCaches();
                        }
                    }
                });
    
                HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
                loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
                OkHttpClient okHttpClient = new OkHttpClient.Builder()
                        .addInterceptor(loggingInterceptor)
    //                    .retryOnConnectionFailure(false)
                        .build();
    
                sImagePipelineConfig = OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient)
    //            sImagePipelineConfig = ImagePipelineConfig.newBuilder(context)
                        .setBitmapsConfig(Bitmap.Config.RGB_565) // 若不是要求忒高清显示应用,就用使用RGB_565吧(默认是ARGB_8888)
                        .setDownsampleEnabled(true) // 在解码时改变图片的大小,支持PNG、JPG以及WEBP格式的图片,与ResizeOptions配合使用
                        // 设置Jpeg格式的图片支持渐进式显示
                        .setProgressiveJpegConfig(new ProgressiveJpegConfig() {
                            @Override
                            public int getNextScanNumberToDecode(int scanNumber) {
                                return scanNumber + 2;
                            }
    
                            public QualityInfo getQualityInfo(int scanNumber) {
                                boolean isGoodEnough = (scanNumber >= 5);
                                return ImmutableQualityInfo.of(scanNumber, isGoodEnough, false);
                            }
                        })
                        .setRequestListeners(requestListeners)
                        .setMemoryTrimmableRegistry(memoryTrimmableRegistry) // 报内存警告时的监听
                        // 设置内存配置
                        .setBitmapMemoryCacheParamsSupplier(new BitmapMemoryCacheParamsSupplier(
                                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)))
                        .setMainDiskCacheConfig(mainDiskCacheConfig) // 设置主磁盘配置
                        .setSmallImageDiskCacheConfig(smallDiskCacheConfig) // 设置小图的磁盘配置
                        .build();
            }
            return sImagePipelineConfig;
        }
    
    }
    
    

    d、替换网络实现为okhttp3

           OkHttpClient okHttpClient = new OkHttpClient.Builder()
                        .addInterceptor(loggingInterceptor)
    //                    .retryOnConnectionFailure(false)
                        .build();
    
                sImagePipelineConfig = OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient)
    

    e、支持调试时,显示图片加载的Log

       FLog.setMinimumLoggingLevel(FLog.VERBOSE);
       Set<RequestListener> requestListeners = new HashSet<>();
       requestListeners.add(new RequestLoggingListener());
    

    f、内存缓存配置完整代码:

    package com.facebook.fresco.helper.config;
    
    import android.app.ActivityManager;
    import android.os.Build;
    
    import com.facebook.common.internal.Supplier;
    import com.facebook.common.util.ByteConstants;
    import com.facebook.fresco.helper.utils.MLog;
    import com.facebook.imagepipeline.cache.MemoryCacheParams;
    
    /**
     * 内存缓存配置
     * https://github.com/facebook/fresco/issues/738
     *
     * Created by android_ls on 16/9/8.
     */
    public class BitmapMemoryCacheParamsSupplier implements Supplier<MemoryCacheParams> {
    
        private final ActivityManager mActivityManager;
    
        public BitmapMemoryCacheParamsSupplier(ActivityManager activityManager) {
            mActivityManager = activityManager;
        }
    
        @Override
        public MemoryCacheParams get() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                return new MemoryCacheParams(getMaxCacheSize(), // 内存缓存中总图片的最大大小,以字节为单位。
                        56,                                     // 内存缓存中图片的最大数量。
                        Integer.MAX_VALUE,                      // 内存缓存中准备清除但尚未被删除的总图片的最大大小,以字节为单位。
                        Integer.MAX_VALUE,                      // 内存缓存中准备清除的总图片的最大数量。
                        Integer.MAX_VALUE);                     // 内存缓存中单个图片的最大大小。
            } else {
                return new MemoryCacheParams(
                        getMaxCacheSize(),
                        256,
                        Integer.MAX_VALUE,
                        Integer.MAX_VALUE,
                        Integer.MAX_VALUE);
            }
        }
    
        private int getMaxCacheSize() {
            final int maxMemory = Math.min(mActivityManager.getMemoryClass() * ByteConstants.MB, Integer.MAX_VALUE);
            MLog.i(String.format("Fresco Max memory [%d] MB", (maxMemory/ByteConstants.MB)));
            if (maxMemory < 32 * ByteConstants.MB) {
                return 4 * ByteConstants.MB;
            } else if (maxMemory < 64 * ByteConstants.MB) {
                return 6 * ByteConstants.MB;
            } else {
                // We don't want to use more ashmem on Gingerbread for now, since it doesn't respond well to
                // native memory pressure (doesn't throw exceptions, crashes app, crashes phone)
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
                    return 8 * ByteConstants.MB;
                } else {
                    return maxMemory / 4;
                }
            }
        }
    
    }
    
    

    g、初始化Fresco

    Fresco.initialize(context,ImageLoaderConfig.getImagePipelineConfig(context));
    

    二、Fresco的各种使用场景

    从网络加载一张图片

    String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
    ImageLoader.loadImage((SimpleDraweeView)findViewById(R.id.sdv_1), url);
    

    1、显示一张图片

        <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/sdv_1"
                android:layout_width="90dp"
                android:layout_height="90dp"
                app:actualImageScaleType="centerCrop"/>
    

    效果图如下:


    2、显示一张圆形图片

      <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/sdv_2"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:layout_marginTop="15dp"
                app:actualImageScaleType="centerCrop"
                app:roundAsCircle="true"/>
    

    效果图如下:


    3、显示一张圆形带边框的图片

            <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/sdv_3"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:layout_marginTop="15dp"
                app:actualImageScaleType="centerCrop"
                app:roundAsCircle="true"
                app:roundingBorderColor="#fff3cf44"
                app:roundingBorderWidth="2dp"/>
    

    效果图如下:


    4、显示一张圆角图片

       <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/sdv_4"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:layout_marginTop="15dp"
                app:actualImageScaleType="centerCrop"
                app:roundAsCircle="false"
                app:roundedCornerRadius="10dp"/>
    

    效果图如下:


    5、显示一张底部是圆角的图片

       <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/sdv_5"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:layout_marginTop="15dp"
                app:actualImageScaleType="centerCrop"
                app:roundAsCircle="false"
                app:roundedCornerRadius="10dp"
                app:roundTopLeft="false"
                app:roundTopRight="false"
                app:roundBottomLeft="true"
                app:roundBottomRight="true"/>
    

    效果图如下:


    6、显示一张左上和右下是圆角的图片

         <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/sdv_6"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:layout_marginTop="15dp"
                app:actualImageScaleType="centerCrop"
                app:roundAsCircle="false"
                app:roundedCornerRadius="10dp"
                app:roundTopLeft="true"
                app:roundTopRight="false"
                app:roundBottomLeft="false"
                app:roundBottomRight="true"/>
    

    效果图如下:


    7、设置占位图

    <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/sdv_7"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:layout_marginTop="15dp"
                app:actualImageScaleType="centerCrop"
                app:placeholderImage="@mipmap/ic_launcher"
                app:placeholderImageScaleType="centerCrop" />
    

    8、带动画的显示(从半透明到不透明)

     <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/sdv_8"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:layout_marginTop="15dp"
                app:actualImageScaleType="centerCrop"
                app:fadeDuration="3000"/>
    

    9、图层叠加显示

     <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/sdv_10"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:layout_marginTop="15dp"
                app:actualImageScaleType="centerCrop"
                app:overlayImage="@mipmap/ic_launcher"/>
    

    10、其它的属性的配置,比如加载进度、加载失败、重试图

       <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/sdv_11"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:layout_marginTop="15dp"
                app:actualImageScaleType="centerCrop"
                app:failureImage="@mipmap/ic_launcher"
                app:failureImageScaleType="centerInside"
                app:retryImage="@mipmap/ic_launcher"
                app:retryImageScaleType="centerCrop"
                app:progressBarImage="@mipmap/ic_launcher"
                app:progressBarImageScaleType="centerCrop"
                app:progressBarAutoRotateInterval="5000"/>
    

    11、从本地文件(比如SDCard上)加载图片

      public static void loadFile(final SimpleDraweeView draweeView, String filePath, final int reqWidth, final int reqHeight) {
            Uri uri = new Uri.Builder()
                    .scheme(UriUtil.LOCAL_FILE_SCHEME)
                    .path(filePath)
                    .build();
            ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
                    .setRotationOptions(RotationOptions.autoRotate())
                    .setLocalThumbnailPreviewsEnabled(true)
                    .setResizeOptions(new ResizeOptions(reqWidth, reqHeight))
                    .build();
            DraweeController controller = Fresco.newDraweeControllerBuilder()
                    .setImageRequest(request)
                    .setOldController(draweeView.getController())
                    .setControllerListener(new BaseControllerListener<ImageInfo>() {
                        @Override
                        public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable anim) {
                            if (imageInfo == null) {
                                return;
                            }
    
                            ViewGroup.LayoutParams vp = draweeView.getLayoutParams();
                            vp.width = reqWidth;
                            vp.height = reqHeight;
                            draweeView.requestLayout();
                        }
                    })
                    .build();
            draweeView.setController(controller);
        }
    

    使用:

    ImageLoader.loadFile((SimpleDraweeView)itemView, photoInfo.thumbnailUrl, 120, 120);
    

    12、从本地资源(Resources)加载图片

      public static void loadDrawable(SimpleDraweeView draweeView, int resId) {
            Uri uri = new Uri.Builder()
                    .scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
                    .path(String.valueOf(resId))
                    .build();
            DraweeController controller = Fresco.newDraweeControllerBuilder()
                    .setUri(uri)
                    .setOldController(draweeView.getController())
                    .build();
            draweeView.setController(controller);
        }
    

    使用:

    ImageLoader.loadDrawable(simpleDraweeView, R.drawable.meizi);
    

    效果图如下:


    13、对图片进行性高斯模糊处理

    public static void loadImageBlur(final SimpleDraweeView draweeView, String url) {
            loadImage(draweeView, url, new BasePostprocessor() {
                @Override
                public String getName() {
                    return "blurPostprocessor";
                }
    
                @Override
                public void process(Bitmap bitmap) {
                    BitmapBlurHelper.blur(bitmap, 35);
                }
            });
        }
    

    其内部调用的方法

    public static void loadImage(SimpleDraweeView simpleDraweeView, String url, BasePostprocessor processor) {
            if (TextUtils.isEmpty(url)) {
                return;
            }
    
            Uri uri = Uri.parse(url);
            ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
                    .setRotationOptions(RotationOptions.autoRotate())
                    .setPostprocessor(processor)
                    .build();
            DraweeController controller = Fresco.newDraweeControllerBuilder()
                    .setImageRequest(request)
                    .setOldController(simpleDraweeView.getController())
                    .build();
            simpleDraweeView.setController(controller);
        }
    

    使用:

      String url = "http://a.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d3de795ad0628535e4dd6fe2.jpg";
    
      SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
      
      simpleDraweeView.setAspectRatio(0.7f);
      
      ViewGroup.LayoutParams lvp = simpleDraweeView.getLayoutParams();
      lvp.width = DensityUtil.getDisplayWidth(this);
    
      ImageLoader.loadImageBlur(simpleDraweeView, url,
                    DensityUtil.getDisplayWidth(this), DensityUtil.getDisplayHeight(this));
    

    效果图如下:


    14、我们知道使用Fresco加载并显示一张图片,需要指定SimpleDraweeView的宽高或者指定其中一个值并设置宽高比,可是我真的不知道要显示的图片有多大,该显示多大?可以帮我搞定吗?答案是肯定的。

            String url = "http://feed.chujianapp.com/20161108/452ab5752287a99a1b5387e2cd849006.jpg@1080w";
            SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
            ImageLoader.loadImage(simpleDraweeView, url, new SingleImageControllerListener(simpleDraweeView));
            
    

    15、从网络加载并显示gif格式的图片

       String url = "http://img4.178.com/acg1/201506/227753817857/227754566617.gif";
    
       SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
       ImageLoader.loadImage(simpleDraweeView, url);
    

    16、加载并显示webp格式的图片

            SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
            ViewGroup.LayoutParams lvp = simpleDraweeView.getLayoutParams();
            lvp.width = DensityUtil.getDisplayWidth(this);
            simpleDraweeView.setAspectRatio(0.6f); // 设置宽高比
    
            ImageLoader.loadDrawable(simpleDraweeView, R.drawable.meizi_webp,
                    DensityUtil.getDisplayWidth(this), DensityUtil.getDisplayHeight(this));
    

    其中R.drawable.meizi_webp为meizi_webp.webp

    17、从内存缓存中移除指定图片的缓存

               if (!TextUtils.isEmpty(photoInfo.originalUrl)) {
                    ImagePipeline imagePipeline = Fresco.getImagePipeline();
                    Uri uri = Uri.parse(photoInfo.originalUrl);
                    if (imagePipeline.isInBitmapMemoryCache(uri)) {
                        imagePipeline.evictFromMemoryCache(uri);
                    }
                }
    

    18、从磁盘缓存中移除指定图片的缓存

            ImagePipeline imagePipeline = Fresco.getImagePipeline();
            Uri uri = Uri.parse(photoInfo.originalUrl);
            // 下面的操作是异步的
            if (imagePipeline.isInDiskCacheSync(uri)) {
                imagePipeline.evictFromDiskCache(uri);
            }
    

    19、清空磁盘缓存

    Fresco.getImagePipeline().clearDiskCaches();
    

    20、清空内存缓存

    Fresco.getImagePipeline().clearMemoryCaches();
    

    21、清空缓存(内存缓存 + 磁盘缓存)

    Fresco.getImagePipeline().clearCaches();
    

    22、在列表视图滚动时,不加载图片,等滚动停止后再开始加载图片,提升列表视图的滚动流畅度。

        // 需要暂停网络请求时调用
        public static void pause(){
            Fresco.getImagePipeline().pause();
        }
    
        // 需要恢复网络请求时调用
        public static void resume(){
            Fresco.getImagePipeline().resume();
        }
    

    23、下载图片存储到指定的路径

      /**
         * 从网络下载图片
         * 1、根据提供的图片URL,获取图片数据流
         * 2、将得到的数据流写入指定路径的本地文件
         *
         * @param url            URL
         * @param loadFileResult LoadFileResult
         */
        public static void downloadImage(Context context, String url, final DownloadImageResult loadFileResult) {
            if (TextUtils.isEmpty(url)) {
                return;
            }
    
            Uri uri = Uri.parse(url);
            ImagePipeline imagePipeline = Fresco.getImagePipeline();
            ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
            ImageRequest imageRequest = builder.build();
    
            // 获取未解码的图片数据
            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() || loadFileResult == null) {
                        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);
                            String photoPath = loadFileResult.getFilePath();
                            Log.i("ImageLoader", "photoPath = " + photoPath);
    
                            byte[] data = StreamTool.read(inputStream);
                            StreamTool.write(photoPath, data);
                            loadFileResult.onResult(photoPath);
                        } catch (IOException e) {
                            loadFileResult.onFail();
                            e.printStackTrace();
                        } finally {
                            imageReference.close();
                            closeableReference.close();
                        }
                    }
                }
    
                @Override
                public void onFailureImpl(DataSource dataSource) {
                    if (loadFileResult != null) {
                        loadFileResult.onFail();
                    }
    
                    Throwable throwable = dataSource.getFailureCause();
                    if (throwable != null) {
                        Log.e("ImageLoader", "onFailureImpl = " + throwable.toString());
                    }
                }
            }, Executors.newSingleThreadExecutor());
        }
    

    使用:

        String url = "http://feed.chujianapp.com/20161108/452ab5752287a99a1b5387e2cd849006.jpg@1080w";
        String filePath = "";
        ImageLoader.downloadImage(context, url, new DownloadImageResult(filePath) {
    
            @Override
            public void onResult(String filePath) {
    
            }
    
            @Override
            public void onFail() {
    
            }
        });
    

    24、不使用SimpleDraweeView组件,但是想使用Fresco去加载图片(两级内存缓存+磁盘缓存要有)并显示到其他组件上(比如显示在TextView的drawableLeft属性上或者显示为View的背景)。

    public static void loadTextDrawable(final TextView view, String url, final int direction, final int iconWidth, final int iconHeight) {
            ImageLoader.loadImage(view.getContext(), url, new LoadImageResult() {
                @Override
                public void onResult(Bitmap bitmap) {
                    Drawable drawable = new BitmapDrawable(view.getContext().getResources(), bitmap);
                    final int width = DensityUtil.dipToPixels(view.getContext(), iconWidth);
                    final int height = DensityUtil.dipToPixels(view.getContext(), iconHeight);
                    drawable.setBounds(0, 0, width, height);
                    switch (direction) {
                        case 0:
                            view.setCompoundDrawables(drawable, null, null, null);
                            break;
                        case 1:
                            view.setCompoundDrawables(null, drawable, null, null);
                            break;
                        case 2:
                            view.setCompoundDrawables(null, null, drawable, null);
                            break;
                        case 3:
                            view.setCompoundDrawables(null, null, null, drawable);
                            break;
                    }
                }
            });
        }
    

    三、推荐的使用方法

    1、第一种用法

    初始化

     Phoenix.init(this); // Context
    

    从网络加载一张图片

    String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    Phoenix.with(simpleDraweeView).load(url);
    

    从本地加载一张图片

    String filePath = "/sdcard/image/test.jpg";
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    Phoenix.with(simpleDraweeView).load(filePath);
    

    从res下面加载一张图片

    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    Phoenix.with(simpleDraweeView).load(R.drawable.meizi);
    

    在写布局文件xml时,我不知道要显示的图片尺寸,需要根据业务逻辑动态的设置要显示的图片的大小,可以像下面这样写:

    String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    Phoenix.with(simpleDraweeView)
           .setWidth(100)
           .setHeight(100)
           .load(url);
    

    只知道要显示图片的高或者宽的值,另一个值可以从设置的比例得出

    String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    Phoenix.with(simpleDraweeView)
           .setWidth(100)
           .setAspectRatio(0.6f) // w/h = 6/10
           .load(url);
    

    图片的高斯模糊处理

    String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    Phoenix.with(simpleDraweeView)
           .setNeedBlur(true)
           .load(url);
    

    加载并显示gif格式的图片

    String url = "http://img4.178.com/acg1/201506/227753817857/227754566617.gif";
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    Phoenix.with(simpleDraweeView)
           .load(url);
    

    加载并显示webp格式的图片

    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    Phoenix.with(simpleDraweeView)
            .load(R.drawable.meizi_webp);
    

    ......

    2、第二种用法

    初始化

     Fresco.initialize(context, ImageLoaderConfig.getImagePipelineConfig(context));
    

    从网络加载一张图片

    String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    ImageLoader.loadImage(simpleDraweeView, url);
    

    从本地加载一张图片

    String filePath = "/sdcard/image/test.jpg";
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    ImageLoader.loadFile(simpleDraweeView, filePath);
    

    从res下面加载一张图片

    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    ImageLoader.loadDrawable(simpleDraweeView, R.drawable.meizi, 100, 100);
    

    在写布局文件xml时,我不知道要显示的图片尺寸,需要根据业务逻辑动态的设置要显示的图片的大小,可以像下面这样写:

    String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    ImageLoader.loadImage(simpleDraweeView, url, 120, 120);
    

    只知道要显示图片的高或者宽的值,另一个值可以从设置的比例得出

    String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    ViewGroup.LayoutParams lvp = simpleDraweeView.getLayoutParams();
    lvp.width = DensityUtil.getDisplayWidth(this); // 取值为手机屏幕的宽度
    simpleDraweeView.setAspectRatio(0.6f); // 设置宽高比
    ImageLoader.loadDrawable(simpleDraweeView, R.drawable.meizi);
    

    图片的高斯模糊处理

    String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    ImageLoader.loadImageBlur(simpleDraweeView, url);
    

    加载并显示gif格式的图片

    String url = "http://img4.178.com/acg1/201506/227753817857/227754566617.gif";
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    ImageLoader.loadImage(simpleDraweeView, url);
    

    加载并显示webp格式的图片

    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
    ImageLoader.loadDrawable(simpleDraweeView, R.drawable.meizi_webp);
    

    ......

    3、大图浏览器
    带动画的效果打开方式,详细细节请查看PhotoWallActivity中的使用

     ArrayList<PhotoInfo> photos = null;
     PictureBrowse.newBuilder(PhotoWallActivity.this)
                  .setParentView(parent)
                  .setCurrentPosition(position)
                  .setPhotoList(photos)
                  .enabledAnimation(true)
                  .build()
                  .start();
    

    无动画效果的打开方式

     ArrayList<PhotoInfo> photos = null;
     PictureBrowse.newBuilder(PhotoWallActivity.this)
                  .setParentView(parent)
                  .setCurrentPosition(position)
                  .setPhotoList(photos)
                  .build()
                  .start();
    

    我提供了两种图片加载使用方式,你想使用那种图片加载方式,全看个人爱好(推荐使用第一种方式)。

    代码我已上传到github上了,地址:https://github.com/hpdx/fresco-helper

    相关文章

      网友评论

      • Magic丶海:如果是gif或者webp动图,要获取图片第一帧的bitmap,怎么处理呢

      本文标题:Android图片加载神器之Fresco,基于各种使用场景的讲解

      本文链接:https://www.haomeiwen.com/subject/mnzlpttx.html