Android base development library to make development easier. DevRing & Demo address: github.com/LJYcoder/De…

Study/Reference address: 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

preface

Fresco is a powerful image loading library from Facebook

Advantages: 1) Automatic memory reclamation. If the image is not visible, it will automatically release the memory occupied in time, avoiding OOM 2) level 3 cache mechanism as much as possible. Two levels of memory cache (decoded and undecoded) + one level of disk cache to improve loading speed and save memory footprint 3) Support various loading scenarios. Such as GIF loading, Gaussian blur and other common image loading scenarios. In addition, it provides unique incremental loading, loading small image before loading large image, loading schedule, etc. (very powerful).

Disadvantages: 1) Bulky (very fat). Larger than other mainstream photo libraries 2) more intrusive. The supplied SimpleDraweeView must be used instead of ImageView to load the display image

In general, Fresco is recommended if your application requires images to be displayed, loaded, etc. But if it’s not that demanding use Glide or another library. Comparison of Fresco and Glide can refer to http://www.jianshu.com/p/6729dc17586b


introduce

Configuration, SimpleDraweeView, loading images, obfuscating, and more.

1. The configuration

1.1 Adding a Dependency

compile 'com. Facebook. Fresco ": the fresco" : 1.5.0'
compile 'com. Facebook. Fresco ": animated - GIF: 1.5.0'// Add this library to load giFs
compile 'com. Facebook. Fresco ": animated - webp: 1.5.0'// Add this library to load webP giFs
compile 'com. Facebook. Fresco ": webpsupport: 1.5.0'// Add this library to support webP
compile 'com. Facebook. Fresco ": imagepipeline - okhttp3:1.5.0'// The network implementation layer uses okHttp3 to add this library
compile 'jp. Wasabeef: fresco "- processors: 2.1.0 @ aar'// Used to provide fresco image transformations
Copy the code

1.2 Configuring Disk Caching

ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setMainDiskCacheConfig(DiskCacheConfig.newBuilder(context)
.setBaseDirectoryPath(context.getExternalCacheDir())// Set the disk cache path
.setBaseDirectoryName(BaseConstants.APP_IMAGE)// Set the name of the disk cache folder
.setMaxCacheSize(MAX_DISK_CACHE_SIZE)// Set the disk cache size
.build());
Copy the code

1.3 Setting Memory Cache

Set up the decoded memory cache (Bitmap cache)

ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setBitmapMemoryCacheParamsSupplier(new Supplier<MemoryCacheParams>() {
       public MemoryCacheParams get(a) {
           int MAX_HEAP_SIZE = (int) Runtime.getRuntime().maxMemory();
           int MAX_MEMORY_CACHE_SIZE = MAX_HEAP_SIZE / 5;// Take 1/5 of the phone's maximum memory as the maximum available memory

           MemoryCacheParams bitmapCacheParams = new MemoryCacheParams( //
                   // Maximum memory available, in bytes
                   MAX_MEMORY_CACHE_SIZE,
                   // Maximum number of images allowed in memory
                   Integer.MAX_VALUE,
                   // The maximum amount of memory, in bytes, available for total images that are ready to be cleaned but not deleted
                   MAX_MEMORY_CACHE_SIZE,
                   // The maximum number of images in memory to be cleared
                   Integer.MAX_VALUE,
                   // Maximum size of a single image in memory
                   Integer.MAX_VALUE);
           returnbitmapCacheParams; }});Copy the code

Set undecoded memory cache

ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setEncodedMemoryCacheParamsSupplier(new Supplier<MemoryCacheParams>() {
       public MemoryCacheParams get(a) {

           MemoryCacheParams bitmapCacheParams;
           // Set the size, refer to the decoded memory cache above
           returnbitmapCacheParams; }});Copy the code

1.4 Setting The Solution for Memory Shortage

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) { 
		         // Clear the memory cacheImagePipelineFactory.getInstance().getImagePipeline().clearMemoryCaches(); }}}); ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context); imagePipelineConfigBuilder.setMemoryTrimmableRegistry(memoryTrimmableRegistry);Copy the code

1.5 Set progressive display effect

ProgressiveJpegConfig progressiveJpegConfig = new ProgressiveJpegConfig() {
	  @Override
	  public int getNextScanNumberToDecode(int scanNumber) {
		  // Returns the number of scans to decode next
	      return scanNumber + 2;
	  }    
	
	  public QualityInfo getQualityInfo(int scanNumber) {
	      boolean isGoodEnough = (scanNumber >= 5);
	      // Determine the number of scans before the image is displayed.
	      return ImmutableQualityInfo.of(scanNumber, isGoodEnough, false); }};/ / specific meaning may refer to http://wiki.jikexueyuan.com/project/fresco/progressive-jpegs.html

ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setProgressiveJpegConfig(progressiveJpegConfig);
// Or use the default effect
//imagePipelineConfigBuilder.setProgressiveJpegConfig(new SimpleProgressiveJpegConfig());
Copy the code

After setting up the effects, you also need to enable progressive loading in ImageRequest, described below.

1.6 Allows resizing images while decoding

If allowed, the size of the decoded image can be adjusted in combination with ResizeOptions in ImageRequest introduced later, so as to optimize the image size. Only JPEG images are supported by default, so set this property to support PNG, JPG, webP.

ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setDownsampleEnabled(true);
Copy the code

1.7 open the Log

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

ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setRequestListeners(requestListeners);
Copy the code

1.8 the initialization

All of the above configuration is done via ImagePipelineConfig and then needs to be initialized in the Application

ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);

/ /... Set up various Settings

ImagePipelineConfig config = imagePipelineConfigBuilder.build();
Fresco.initialize(context, config);
Copy the code

If you want to use the default configuration, you can

Fresco.initialize(context);
Copy the code

2. SimpleDraweeView

Fresco requires that images be loaded and displayed using SimpleDraweeView instead of ImageView, which is why some people don’t want to use Fresco. The following describes the various attributes of SimpleDraweeView in XML

// Add XMLNS :fresco= to the outermost layout properties"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"/>

Copy the code

The role of the above attributes: (from http://www.jianshu.com/p/8ff81be83101)

attribute Role that
actualImageScaleType Load the zoom style of the finished image
fadeDuration The time interval used to transition from progress bar and placeholder images to finished loading images
failureImage The image used by the failed load
failureImageScaleType The zoom style of the picture used by the failed load
placeholderImage Placeholder picture
placeholderImageScaleType The zoom style of the placeholder picture
progressBarAutoRotateInterval Rotate The progress bar Indicates the time required for one rotation
progressBarImage Rotate the picture used by the progress bar
progressBarImageScaleType The zoom style of the picture used to rotate the progress bar
retryImage Retry the image used
retryImageScaleType Retry the zoom style of the image being used
backgroundImage The background image
overlayImage The overlay image over the image after loading
pressedStateOverlayImage Overlay image in press state
roundAsCircle Whether to cut the picture to a circle
roundedCornerRadius The radius of a rounded corner in a rounded picture
roundTopLeft Whether the upper left corner is rounded
roundTopRight Whether the upper right corner is rounded
roundBottomLeft Whether the lower left corner is rounded
roundBottomRight Whether the lower right corner is rounded
roundWithOverlayColor Rounded corners or circles overlay color, can only be color
roundingBorderWidth The width of the border of a rounded or circular drawing
roundingBorderColor The color of the border of a rounded corner or circle
viewAspectRatio Set the aspect ratio

Each attribute renderings, to http://blog.csdn.net/wyb112233/article/details/49637685 to view, I will not repeat the wheels. The android: SRC attribute is invalid for SimpleDraweeView, use fresco:placeholderImage if necessary. 2) SimpleDraweeView does not support android:layout_width and Android :layout_height both set to wrap_content.

3. Load the image

Loading images with Fresco roughly follows this process.

  1. Hierarchay (Attributes in the XML above and display load progress bar etc., can be set here)
  2. Build ImageRequest (load paths, enable progressive loading, transform images, resize decoded images, etc., can be set here)
  3. Build DraweeController (GIF load, reload after failure, etc., can be set here)
  4. Loading images

3.1 set Hierarchay

Although all the properties in the XML can be set in this step through code, there are generally only fixed properties set here, such as load placeholder, load failure graph, and so on. In addition, the loading progress of images is also set here.

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 is set, such as the images displayed in various states
public void setHierarchay(GenericDraweeHierarchy hierarchy) {
    if(hierarchy ! =null) {
        // Reload the displayed image
        hierarchy.setRetryImage(retryImage); 
        // Failed to load the image displayed
        hierarchy.setFailureImage(failureImage, ScalingUtils.ScaleType.CENTER_CROP); 
        // Placeholder map displayed before loading is complete
        hierarchy.setPlaceholderImage(placeholderImage, ScalingUtils.ScaleType.CENTER_CROP);
        // Set the zoom mode of the image after loading successfully
        hierarchy.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP);

        // Display the loading progress bar using the new ProgressBarDrawable()
        // It is displayed at the bottom of the image by default. You can set the color of the progress bar.
        hierarchy.setProgressBarImage(new ProgressBarDrawable());
        // Set the image load to a circle
        hierarchy.setRoundingParams(RoundingParams.asCircle());
        // Set the image load to rounded corner, and can set the rounded corner size
        hierarchy.setRoundingParams(RoundingParams.fromCornersRadius(radius));

		// For other Settings, please check the specific API.}}Copy the code

3.2 build ImageRequest

/** * Build ImageRequest *@paramUri load path *@paramSimpleDraweeView loaded image control *@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();
    }

    // Generate the constructor for ImageRequest based on the request path
    ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
    // Resize the decoded image
    if (width > 0 && height > 0) {
        builder.setResizeOptions(new ResizeOptions(width, height));
    }
    // Set whether to enable progressive loading, JPEG only
    builder.setProgressiveRenderingEnabled(true);

    // Image transform processing
    CombinePostProcessors.Builder processorBuilder = new CombinePostProcessors.Builder();
    // Add a fuzzy transform
    processorBuilder.add(new BlurPostprocessor(context, radius));
    // Add the whiter transform
    processorBuilder.add(new GrayscalePostprocessor());
    // Apply the added transform
    builder.setPostprocessor(processorBuilder.build());
    / / transform to see https://github.com/wasabeef/fresco-processors for more pictures
    return builder.build();
}
Copy the code

3.3 build DraweeController

/** * Build and get Controller *@param request
* @param oldController
* @return* /
public DraweeController getController(ImageRequest request, @Nullable DraweeController oldController) {

   PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder();
   builder.setImageRequest(request);// Set the image request
   builder.setTapToRetryEnabled(false);// Set whether to allow reload when loading fails
   builder.setAutoPlayAnimations(true);// Sets whether to allow the animation to play automatically
   builder.setOldController(oldController);
   return builder.build();
}
Copy the code

3.4 Loading images

Create a loadImage method to string the Hierarchy, ImageRequest, and DraweeController together for specific loading scenarios

/** * load the image core method **@paramSimpleDraweeView Image loading control *@paramUri Image loading address */
public void loadImage(SimpleDraweeView simpleDraweeView, Uri uri) {
  / / set up the Hierarchy
   setHierarchay(simpleDraweeView.getHierarchy());
   // Build and get ImageRequest
   ImageRequest imageRequest = getImageRequest(uri, simpleDraweeView);
   // Build and get Controller
   DraweeController draweeController = getController(imageRequest, simpleDraweeView.getController());
   // Start loading
   simpleDraweeView.setController(draweeController);
}
Copy the code

Specific loading scenarios:

  • Load web images, including GIFs/Webp giFs
 public void loadNetImage(SimpleDraweeView simpleDraweeView, String url) {
     Uri uri = Uri.parse(url);
     loadImage(simpleDraweeView, uri);
 }
Copy the code
  • Load local file images
public void loadLocalImage(SimpleDraweeView simpleDraweeView, String fileName) {
    Uri uri = Uri.parse("file://" + fileName);
    loadImage(simpleDraweeView, uri);
}
Copy the code
  • Load resource images under RES
public void loadResourceImage(SimpleDraweeView simpleDraweeView, @DrawableRes int resId) {
    Uri uri = Uri.parse("res:///" + resId);
    loadImage(simpleDraweeView, uri);
}
Copy the code
  • Load the image under the ContentProvider
public void loadContentProviderImage(SimpleDraweeView simpleDraweeView, int resId) {
    Uri uri = Uri.parse("content:///" + resId);
    loadImage(simpleDraweeView, uri);
}
Copy the code
  • Load the image under asset
public void loadAssetImage(SimpleDraweeView simpleDraweeView, int resId) {
    Uri uri = Uri.parse("asset:///" + resId);
    loadImage(simpleDraweeView, uri);
}
Copy the code
  • To load network images, load the small image first and replace the small image after the large image is loaded

This requires modifying the DraweeController build to add the small graph request via setLowResImageRequest

public DraweeController getSmallToBigController(ImageRequest smallRequest, ImageRequest bigRequest, @Nullable DraweeController oldController) {

    PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder();
    builder.setLowResImageRequest(smallRequest);// Small image request
    builder.setImageRequest(bigRequest);// Large image request
    builder.setTapToRetryEnabled(false);// Set whether to allow reload when loading fails
    builder.setAutoPlayAnimations(true);// Sets whether to allow the animation to play automatically
    builder.setOldController(oldController);
    return builder.build();
}
Copy the code
public void loadImageSmallToBig(SimpleDraweeView simpleDraweeView, Uri smallUri, Uri bigUri) {
	/ / set up the Hierarchy
    setHierarchay(simpleDraweeView.getHierarchy());
    // Image request to build a small diagram
    ImageRequest smallRequest = getImageRequest(smallUri, simpleDraweeView);
    // Image request to build a large image
    ImageRequest bigRequest = getImageRequest(bigUri, simpleDraweeView);
    / / build Controller
    DraweeController draweeController = getSmallToBigController(smallRequest, bigRequest, simpleDraweeView.getController());
    // Start loading
    simpleDraweeView.setController(draweeController);
}
Copy the code
// Load the network image, load the small image first, wait for the large image to complete the replacement
public void loadNetImageSmallToBig(SimpleDraweeView simpleDraweeView, String smallUrl, String bigUrl) {
    Uri smallUri = Uri.parse(smallUrl);
    Uri bigUri = Uri.parse(bigUrl);
    loadImageSmallToBig(simpleDraweeView, smallUri, bigUri);
}
Copy the code

4. Confused

Add the following to the proGuard-rules. pro file for obfuscation configuration

# fresco "start-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.ExecutorSup plier); }# end of fresco"
Copy the code

5. Other

5.1 Cache Policy

Fresco uses a three-level cache mechanism, consisting of two levels of memory and one level of disk cache. The two levels of memory are divided into Bitmap and undecoded images. Let’s look at the caching strategy through the load process.

  1. Look for a Bitmap in the decoded image cache based on the Uri. If present, return Bitmap display; If not, look it up in the undecoded image cache.
  2. If the corresponding data exists in the undecoded image cache, decode, return the Bitmap display and add it to the decoded image cache; If not, look it up in the disk cache.
  3. If the corresponding data exists in the disk cache, the data is added to the undecoded image cache, and then decoded, returning the Bitmap display and adding it to the decoded image cache; If not, make a network request or load to a local file.
  4. After a successful request or load, the data is added to the disk cache and the undecoded image cache, and then decoded, returning the Bitmap display and adding it to the decoded image cache.

    Simple whole schematic diagram, to help understand:

5.2 Compatible with Shared Animation

Shared animation was added after android5.0. http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0201/2394.html http://jcodecraeer.com/a/opensource/2015/0113/2311.html?1422794518

If you combine Fresco and shared animation directly to create transitions on your page, you may find them invalid or abnormal. The Fresco official explanation is also available at https://www.fresco-cn.org/docs/shared-transitions.html

Compatibility: 1. Rewrite the XML file that shares the animation transformation effect, comment out the changeImageTransform, and put this file in the RES/Transition folder

<? xml version="1.0" encoding="utf-8"? > <transitionSet xmlns:android="http://schemas.android.com/apk/res/android"> <explode/> <changeBounds/> <changeTransform/> <changeClipBounds/> <! --<changeImageTransform/>--> <! -- The Fresco image framework does not support changeImageTransform. By default, all five transformations are used, so you need to rewrite the XML and comment out changeImageTransform --> </transitionSet>Copy the code

2. Use the XML file overridden in the previous step in the style file

<? xml version="1.0" encoding="utf-8"? > <resources> <style name="AppTheme" parent="AppTheme.Base"> <! -- Transitions -> <item name= is allowed"android:windowContentTransitions">true</item> <! -- Specify shared Element transitions --> <item name="android:windowSharedElementEnterTransition">
        @transition/share_element_transition</item>
        <item name="android:windowSharedElementExitTransition">
        @transition/share_element_transition</item>
    </style>
</resources>
Copy the code

5.3 Viewing the Larger View

“Click on the smaller image to view the larger image, and the larger image supports zooming.” This requirement is common; the SimpleDraweeView mentioned above doesn’t support zooming and so on, so you need to customize a control to display it. A ZoomableDraweeView is provided to support this scene, and you can also refer to the PhotoDraweeView

5.4 Obtaining the Bitmap returned from the Network Request

Sometimes, we need to get the Bitmap object back from the network request, so we can do this:

// Load the image and get the returned Bitmap in the ImageListener callback
public void getBitmap(Context context, String url, final ImageListener<Bitmap> imageListener) {
    / / reference from https://github.com/hpdx/fresco-helper/blob/master/fresco-helper/src/main/java/com/facebook/fresco/helper/ImageLoade r.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();
                    // GIF processing
                    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); }}}// Non-gif processing
                    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());
}
Copy the code

Or if there is data in the cache, it can be fetched from the cache and converted into a Bitmap

FileBinaryResource resource = (FileBinaryResource) Fresco.getImagePipelineFactory().getMainFileCache().getResource(new SimpleCacheKey(url));
if(resource ! =null&& resource.getFile() ! =null) {
    Bitmap bitmap = BitmapFactory.decodeFile(resource.getFile().getAbsolutePath());
}
Copy the code

5.5 Downloading Images

Download the image to the specified location and get the download result in the ImageListener callback

public void downLoadImage(Context context, String url, final File saveFile, final ImageListener<File> imageListener) {
    / / reference from https://github.com/hpdx/fresco-helper/blob/master/fresco-helper/src/main/java/com/facebook/fresco/helper/ImageLoade r.java
    Uri uri = Uri.parse(url);
    ImagePipeline imagePipeline = Fresco.getImagePipeline();
    ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
    ImageRequest imageRequest = builder.build();

    // Get undecoded image data
    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 download progress:" + progress);
        }

        @Override
        public void onFailureImpl(DataSource dataSource) {
            Throwable throwable = dataSource.getFailureCause();
            if(imageListener ! =null) {
                imageListener.onFail(throwable);
            }
        }
    }, Executors.newSingleThreadExecutor());
}

Copy the code

The demo encapsulates the previous configuration, the methods for loading images, and so on in the FrescoManager class