当前位置: 首页 > 工具软件 > Fresco > 使用案例 >

Fresco用法详解

范振海
2023-12-01

版权声明:本文为延成原创文章,转载请标明出处

Fresco用法详解

经过在实际项目中多次的使用,本人在这做了一下简单总结,希望对初次使用和正在使用的你们有所帮助。

官方地址

官方github地址:https://github.com/facebook/fresco
官方地址:https://www.fresco-cn.org/

fresco优缺点

优点:

  1. 内存管理,三级缓存设计
  2. 图片预览,渐进式显示效果和多图请求
  3. 图片呈现效果,支持Gif、WebP格式
  4. 第一次加载和加载缓存速度都比较快

缺点:

  1. 库体积太大,3.5M左右(减少库体积办法:项目中用不到的库不做引用,并对fresco进行代码混淆)

fresco基本使用

1.gradle引用


	 dependencies {
	 //基础功能引用
	 compile 'com.facebook.fresco:fresco:0.14.1'
	 //支持GIF动图,需要添加
	 compile 'com.facebook.fresco:animated-gif:0.14.1'
	 //支持WebP动图,需要添加
	 compile 'com.facebook.fresco:animated-webp:0.14.1'
	 //支持WebP静态图,需要添加
	 compile 'com.facebook.fresco:webpsupport:0.14.1'
     //支持okhttp3,需要添加
	 compile 'com.facebook.fresco:imagepipeline-okhttp3:0.14.1'
	 }

2.初始化并配置fresco

在Application中做初始化


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

自定义配置ImageLoaderConfig类


	/**
	 * Created by corleone.
	 */
	
	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();
	
	                    if (MemoryTrimType.OnCloseToDalvikHeapLimit.getSuggestedTrimRatio() == suggestedTrimRatio
	                            || MemoryTrimType.OnSystemLowMemoryWhileAppInBackground.getSuggestedTrimRatio() == suggestedTrimRatio
	                            || MemoryTrimType.OnSystemLowMemoryWhileAppInForeground.getSuggestedTrimRatio() == suggestedTrimRatio
	                            ) {
	                        // 清除内存缓存
	                        Fresco.getImagePipeline().clearMemoryCaches();
	                    }
	                }
	            });
	
	            OkHttpClient okHttpClient = new OkHttpClient.Builder()
	                    .retryOnConnectionFailure(false)
	                    .build();
	
	            sImagePipelineConfig = OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient)
	//                    .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)))
	                    .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;
	                        }
	                    })
	                    .setEncodedMemoryCacheParamsSupplier(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;
	                        }
	                    })
	                    .setMainDiskCacheConfig(mainDiskCacheConfig) // 设置主磁盘配置
	                    .setSmallImageDiskCacheConfig(smallDiskCacheConfig) // 设置小图的磁盘配置
	                    .build();
	        }
	        return sImagePipelineConfig;
	    }
	}

3.在xml中基本使用


	<com.facebook.drawee.view.SimpleDraweeView
	    android:id="@+id/sdv_head"
	    android:layout_width="60dp"
	    android:layout_height="60dp"
	    fresco:placeholderImage="@mipmap/ic_launcher"
	  />
	  
	//在布局根节点添加
	xmlns:fresco="http://schemas.android.com/apk/res-auto"

4.代码中基本加载


	Uri uri = Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/fresco-logo.png");
	SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);
	draweeView.setImageURI(uri);

fresco高级使用

1.在XML中高级使用SimpleDraweeView:


	<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"
	  />
	 

2.在代码中的高级使用,为了方便本人已经封装成Fresco工具类


	/**
	 * Created by corleone.
	 */
	
	public class FrescoUtils {
	
	    /**
	     * 显示http或者https远程图片。
	     *
	     * @param draweeView imageView。
	     * @param url        连接地址。
	     */
	    public static void showUrl(SimpleDraweeView draweeView, String url) {
	        if (TextUtils.isEmpty(url))
	            draweeView.setImageURI(Uri.parse("res:///" + R.drawable.bg_rect_placeholder_main_gray));
	        try {
	            draweeView.setImageURI(Uri.parse(url));
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	
	    /**
	     * 显示远程图并加入自定义旋转动画
	     * 
	     * @param draweeView
	     * @param url
	     */
	    public static void showUrlAnima(SimpleDraweeView draweeView, String url) {
	
	        if (TextUtils.isEmpty(url))
	            draweeView.setImageURI(Uri.parse("res:///" + R.drawable.bg_rect_placeholder_main_gray));
	        try {
	            draweeView.setImageURI(Uri.parse(url));
	            Animation animation = AnimationUtils.loadAnimation(HiMicApplication.getInstance(), R.anim.rotate_anim);
	            draweeView.setAnimation(animation);
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	
	    /**
	     * 显示bitmap图
	     * 
	     * @param context
	     * @param draweeView
	     * @param mBitmap
	     */
	    public static void showBitmap(Context context, SimpleDraweeView draweeView, Bitmap mBitmap) {
	        Uri uri = null;
	        if (mBitmap == null) {
	            draweeView.setImageURI(Uri.parse("res:///" + R.drawable.bg_rect_placeholder_main_gray));
	        } else {
	             uri = Uri.parse(MediaStore.Images.Media.insertImage(context.getContentResolver(), mBitmap, null, null));
	        }
	        try {
	            draweeView.setImageURI(uri);
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	
	    /**
	     * 显示远程图,并对图做圆角处理
	     * 为了防止builder被多次new,所以用到时传进来
	     *GenericDraweeHierarchyBuilder mBuilder = new GenericDraweeHierarchyBuilder(context.getResources());
	     
	     * @param draweeView
	     * @param url
	     * @param builder
	     * @param corners
	     */
	    public static void showCornerUrl(SimpleDraweeView draweeView, String url, GenericDraweeHierarchyBuilder builder,int corners) {
	        RoundingParams roundingParams = new RoundingParams();
	        roundingParams.setCornersRadii(corners, corners, corners, corners);
	        GenericDraweeHierarchy hierarchy = builder
	                .setActualImageScaleType(ScalingUtils.ScaleType.FOCUS_CROP)
	                .setFailureImageScaleType(ScalingUtils.ScaleType.CENTER_INSIDE)
	                .build();
	        hierarchy.setRoundingParams(roundingParams);
	        draweeView.setHierarchy(hierarchy);
	        if (url == null)
	            draweeView.setImageURI(Uri.parse("res:///" + R.drawable.bg_rect_placeholder_main_gray));
	        try {
	            draweeView.setImageURI(Uri.parse(url));
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	
	    /**
	     * 清除指定图片url缓存
	     * 
	     * @param draweeView
	     * @param url
	     */
	    public static void clearCacheShowUrl(SimpleDraweeView draweeView, String url) {
	        if (TextUtils.isEmpty(url))
	            return;
	
	        Uri uri = Uri.parse(url);
	        ImagePipeline imagePipeline = Fresco.getImagePipeline();
	        imagePipeline.evictFromMemoryCache(uri);
	        imagePipeline.evictFromDiskCache(ImageRequest.fromUri(uri));
	
	        // combines above two lines
	        imagePipeline.evictFromCache(uri);
	        try {
	            draweeView.setImageURI(Uri.parse(url));
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	
	
	    /**
	     * 显示一个本地图片。
	     *
	     * @param draweeView imageView。
	     * @param path       路径。
	     * @param width      实际宽。
	     * @param height     实际高度。
	     */
	    public static void showFile(SimpleDraweeView draweeView, String path, int width, int height) {
	        try {
	            Uri uri = Uri.parse("file://" + path);
	            ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
	                    .setResizeOptions(new ResizeOptions(width, height))
	                    .build();
	            AbstractDraweeController controller = Fresco.newDraweeControllerBuilder()
	                    .setOldController(draweeView.getController())
	                    .setImageRequest(request)
	                    .build();
	            draweeView.setController(controller);
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	
	    /**
	     * 显示本地图片。
	     *
	     * @param draweeView imageView。
	     * @param path       路径。
	     */
	    public static void showFile(SimpleDraweeView draweeView, String path) {
	        try {
	            Uri uri = Uri.parse("file://" + path);
	            draweeView.setImageURI(uri);
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	
	    /**
	     * 显示一个Res中的图片。
	     *
	     * @param draweeView ImageView。
	     * @param resId      资源ID。
	     */
	    public static void showRes(SimpleDraweeView draweeView, @DrawableRes int resId) {
	        try {
	            draweeView.setImageURI(Uri.parse("res:///" + resId));
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	
	    /**
	     * 显示content provider图片。
	     *
	     * @param draweeView image view。
	     * @param path       路径。
	     */
	    public static void showContentProvider(SimpleDraweeView draweeView, String path) {
	        try {
	            draweeView.setImageURI(Uri.parse("content://" + path));
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	
	    /**
	     * 显示Assets中的图片。
	     *
	     * @param draweeView ImageView.
	     * @param path       路径。
	     */
	    public static void showAsset(SimpleDraweeView draweeView, String path) {
	        try {
	            draweeView.setImageURI(Uri.parse("asset://" + path));
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	
	    /**
	     * 以高斯模糊显示。
	     *
	     * @param draweeView View。
	     * @param url        url.
	     * @param iterations 迭代次数,越大越魔化。
	     * @param blurRadius 模糊图半径,必须大于0,越大越模糊。
	     */
	    public static void showUrlBlur(SimpleDraweeView draweeView, String url, int iterations, int blurRadius) {
	        try {
	            Uri uri = Uri.parse(url);
	            ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
	                    .setPostprocessor(new IterativeBoxBlurPostProcessor(iterations, blurRadius))
	                    .build();
	            AbstractDraweeController controller = Fresco.newDraweeControllerBuilder()
	                    .setOldController(draweeView.getController())
	                    .setImageRequest(request)
	                    .build();
	            draweeView.setController(controller);
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	
	    /**
	     * 加载图片成bitmap。
	     *
	     * @param imageUrl 图片地址。
	     */
	    public static void loadToBitmap(String imageUrl, BaseBitmapDataSubscriber mDataSubscriber) {
	        ImageRequest imageRequest = ImageRequestBuilder
	                .newBuilderWithSource(Uri.parse(imageUrl))
	                .setProgressiveRenderingEnabled(true)
	                .build();
	
	        ImagePipeline imagePipeline = Fresco.getImagePipeline();
	        DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage
	                (imageRequest, HiMicApplication.getInstance());
	        dataSource.subscribe(mDataSubscriber, CallerThreadExecutor.getInstance());
	    }
	
	    /**
	     * 图片拷贝
	     *
	     * @param imgUrl
	     * @param newPath
	     * @param fileName
	     * @return
	     */
	    public static boolean copyPicFile(String imgUrl, String newPath, String fileName) {
	        FileBinaryResource fileBinaryResource = (FileBinaryResource) Fresco.getImagePipelineFactory()
	                .getMainFileCache().getResource(new SimpleCacheKey(imgUrl));
	        if (fileBinaryResource == null) {
	            return false;
	        }
	        File oldfile = fileBinaryResource.getFile();
	        boolean isok = true;
	        try {
	            int bytesum = 0;
	            int byteread = 0;
	            if (oldfile.exists()) { //文件存在时
	                InputStream inStream = new FileInputStream(oldfile); //读入原文件
	                if (!new File(newPath).exists()) {
	                    new File(newPath).mkdirs();
	                }
	                String myPath = newPath + File.separator + fileName;
	                FileOutputStream fs = new FileOutputStream(myPath);
	                byte[] buffer = new byte[1024];
	                int length;
	                while ((byteread = inStream.read(buffer)) != -1) {
	                    bytesum += byteread; //字节数 文件大小
	                    fs.write(buffer, 0, byteread);
	                }
	                fs.flush();
	                fs.close();
	                inStream.close();
	            } else {
	                isok = false;
	            }
	        } catch (Exception e) {
	            isok = false;
	        }
	        return isok;
	    }
	
	    /**
	     * 加载 GIF 图
	     * 
	     * @param url
	     * @param mSimpleDraweeView
	     */
	    public static void loadImageGif(String url, SimpleDraweeView mSimpleDraweeView) {
	        DraweeController controller = Fresco.newDraweeControllerBuilder()
	                .setUri(Uri.parse(url))
	                .setAutoPlayAnimations(true)
	                .build();
	        mSimpleDraweeView.setController(controller);
	    }
	
	    /**
	     * 设置view大小。
	     * @param view  View。
	     * @param width 指定宽。
	     * @param width 指定高。
	     */
	    public static void requestLayout(View view, int width, int height) {
	        ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
	        if (layoutParams == null) {
	            layoutParams = new ViewGroup.LayoutParams(width, height);
	            view.setLayoutParams(layoutParams);
	        } else {
	            view.getLayoutParams().width = width;
	            view.getLayoutParams().height = height;
	            view.requestLayout();
	        }
	    }
	}

fresco代码混淆

在proguard-rules.pro中加入


	# Keep our interfaces so they can be used by other ProGuard rules.
	# See http://sourceforge.net/p/proguard/bugs/466/
	-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
	-keep,allowobfuscation @interface com.facebook.soloader.DoNotOptimize
	
	# Do not strip any method/class that is annotated with @DoNotStrip
	-keep @com.facebook.common.internal.DoNotStrip class *
	-keepclassmembers class * {
	    @com.facebook.common.internal.DoNotStrip *;
	}
	
	# Do not strip any method/class that is annotated with @DoNotOptimize
	-keep @com.facebook.soloader.DoNotOptimize class *
	-keepclassmembers class * {
	    @com.facebook.soloader.DoNotOptimize *;
	}
	
	# Keep native methods
	-keepclassmembers class * {
	    native <methods>;
	}
	
	-dontwarn okio.**
	-dontwarn com.squareup.okhttp.**
	-dontwarn okhttp3.**
	-dontwarn javax.annotation.**
	-dontwarn com.android.volley.toolbox.**
	-dontwarn com.facebook.infer.**

因为fresco引起的在arm64位机器上找不到对应的so库


	android {
		splits {
	        abi {
	            enable true
	            reset()
	            include 'x86', 'x86_64', 'armeabi-v7a', 'armeabi'//不能保留arm64-v8a
	            //include 'armeabi-v7a'//或者只保留armeabi-v7a
	            universalApk false
	        }
	    }
	}

解释:

	enable: enables the ABIs split mechanism
	exclude: By default all ABIs are included, you can remove some ABIs.
	include: indicate which ABIs to be included
	reset(): reset the list of ABIs to be included to an empty string (this allows, in conjunctions with include, to indicate which one to use rather than which ones to ignore)
	universalApk: indicates whether to package a universal version (with all ABIs) or not. Default is false.
 类似资料: