Fresco is a powerful library for displaying images in Android, supporting applications all the way back to GingerBread (API 9). It downloads and caches remote images in a memory efficient manner, using a special region of non-garbage collected memory on Android called ashmem
.
When working with Fresco, it's helpful to be familiar with the following terms:
ImageView
, but only for convenience (see the gotchas below for more info on this). Most of the time you'll be using a SimpleDraweeView
in your code.ImagePipeline
.First, make sure to add the Fresco dependency in your app/build.gradle file:
dependencies {
implementation 'com.facebook.fresco:fresco:1.10.0'
}
Then, in your AndroidManifest.xml
make you have the Internet permission if you plan to fetch any images from the network:
<uses-permission android:name="android.permission.INTERNET"/>
Next, make sure to initialize Fresco. Fresco needs to be initialized before you call setContentView()
in any Activity
that uses Fresco
.
Fresco.initialize(context);
And then include it in your layout:
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdvImage"
android:layout_width="130dp"
android:layout_height="130dp"
fresco:placeholderImage="@drawable/myPlaceholderImage" />
Note: If you want to use any Fresco defined properties, you'll need to add a custom namespace definition:
xmlns:fresco="http://schemas.android.com/apk/res-auto"
Finally, set the actual image URI:
Uri imageUri = Uri.parse("https://i.imgur.com/tGbaZCY.jpg");
SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.sdvImage);
draweeView.setImageURI(imageUri);
That's all you need to get started using Fresco, but Fresco can do much more than that. Below you can find a majority of the properties that Fresco supports.
<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" />
Note: DraweeView doesn't support specifying wrap_content
for the layout_width
or layout_height
attributes. This is to prevent situations where your placeholder image might be a different size than your actual image, forcing Android to do another layout pass once the actual image comes in.
There is only one case where DraweeView supports wrap_content
and this is for the helpful viewAspectRatio
property, allowing you to configure an aspect ratio.
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/my_image_view"
android:layout_width="20dp"
android:layout_height="wrap_content"
fresco:viewAspectRatio="1.33" />
You can read more about Fresco's capabilities in the Fresco docs.
Getting the bitmap out of a SimpleDraweeView requires working with the ImagePipeline
instead of the DraweeView
itself. The code below shows how to get a bitmap out of the ImagePipeline
, which comes in useful when you want to share an image with another user.
ImagePipeline imagePipeline = Fresco.getImagePipeline();
ImageRequest imageRequest = ImageRequestBuilder
.newBuilderWithSource(imageUri)
.setRequestPriority(Priority.HIGH)
.setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH)
.build();
DataSource<CloseableReference<CloseableImage>> dataSource =
imagePipeline.fetchDecodedImage(imageRequest, mContext);
try {
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
public void onNewResultImpl(@Nullable Bitmap bitmap) {
if (bitmap == null) {
Log.d(TAG, "Bitmap data source returned success, but bitmap null.");
return;
}
// The bitmap provided to this method is only guaranteed to be around
// for the lifespan of this method. The image pipeline frees the
// bitmap's memory after this method has completed.
//
// This is fine when passing the bitmap to a system process as
// Android automatically creates a copy.
//
// If you need to keep the bitmap around, look into using a
// BaseDataSubscriber instead of a BaseBitmapDataSubscriber.
}
@Override
public void onFailureImpl(DataSource dataSource) {
// No cleanup required here
}
}, CallerThreadExecutor.getInstance());
} finally {
if (dataSource != null) {
dataSource.close();
}
}
Make sure to add the following permissions to your AndroidManifest.xml
:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Note: The permissions model has changed starting in Marshmallow. If your targetSdkVersion
>= 23
and you are running on a Marshmallow (or later) device, you may need to enable runtime permissions. You can also read more about the runtime permissions changes here.
To share an image from Fresco, you first need to get the bitmap from the ImagePipeline
. Then you can use the following code to save the bitmap to the Media image store and pass the path into a share intent.
public void shareBitmap(Bitmap bitmap) {
String path = MediaStore.Images.Media.insertImage(mContext.getContentResolver(),
bitmap, "Image Description", null);
Uri bmpUri = Uri.parse(path);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, bmpUri);
shareIntent.setType("image/*");
mContext.startActivity(Intent.createChooser(shareIntent, "Share Image"));
}
See the guide on sharing if you want to read more about the different sharing options.
Make sure you review the list of gotchas in the Fresco documentation. The most notable one is to avoid ImageView
methods and properties when dealing with a DraweeView
(even though DraweeView
extends ImageView
).
setImageBitmap
, setImageDrawable
, etc as this will wipe out the DraweeHierarchy
ImageView
properties like scaleType
, src
, etc. Instead use the DraweeView counterparts for these properties.