My Experience using Fresco
Fresco is an Image Management Library for Android by Facebook. I recently worked on Replacing UIL (Universal Image Loader) with Fresco in an Android App. I would like to share my experience in doing so and some of the learnings that might help you if you plan to use Fresco.
If you don’t know what Fresco is yet, please look at the github repository https://github.com/facebook/fresco and official site http://frescolib.org/
If you are new to Fresco, I recommend you read article by Facebook https://code.facebook.com/posts/366199913563917/introducing-fresco-a-new-image-library-for-android/. It clearly explains the motive behind Fresco, its implementation, different memory regions in Android than an App might use and the way Fresco works.
In this article I will be explaining about things that you may not find in Fresco documentation but you might need them in a fairly complex application.
Massive improvement in OutOfMemory in Android 4.x and below
Fresco has three levels of caching
- Bitmap cache
- Encoded memory cache
- Disk cache
On Android 4.x and lower, the bitmap cache’s data lives in the ashmem heap, not in the Java heap. This means that images don’t force extra runs of the garbage collector, slowing down your app. You will observe a big improvement in OutOfMemory error in Android 4.x and lower.
Android 5.0 has much improved memory management than earlier versions, so it is safer to leave the bitmap cache on the Java heap.
More about Caching in Fresco http://frescolib.org/docs/caching.html
The Hard part
Note that if you want to replace UIL or Picasso with Fresco you will have to edit all the layout files using ImageViews which load images from network. You will have to replace ImageView with SimpleDraweeView.
Also note SimpleDraweeView does not support the wrap_content to be used for both Layout Height and Width together http://frescolib.org/docs/using-drawees-xml.html#wrap-content. Keep these limitations in mind when you want to replace the existing image download library with Fresco. You will have to create a GenericDraweeHierarchy to set things like placeholder.
GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(mContext.getResources());
builder.setPlaceholderImage(mContext.getResources().getDrawable(R.drawable.my_drawable));
myDraweeView.setHierarchy(builder.build());
Below are some of the useful tips and code that might be useful if you are planning to use Fresco in your next project. These are the difficulties faced and some possible solutions.
Downloading Bitmaps
One of the limitations of Fresco is that image request can be attached to only DraweeView and its subclasses. Right now there is no way to attach image request to ImageView or custom views extending ImageView.
One way to handle this is to download the bitmap and set this bitmap to ImageView / custom view.
But this approach is not very direct. One way is to do this is to have a method in a helper class to return a CloseableReference of type CloseableImage (imageReference in the code below) in a callback ( don’t try to read the bitmap and return bitmap ). Reason why CloseableReference is returned not the actual bitmap is because Fresco recycles the bitmap if there are no reference to bitmap. The underlining bitmap can me read from CloseableReference from Activity / Fragment.
Below is one of the ways you can do it
IBitmapDownloader is a simple interface with callbacks.
In the Activity or Fragment maintain a map of urls and corresponding CloseableReference
Map<String, CloseableReference<CloseableImage>> imageRefMap = new HashMap<String, CloseableReference<CloseableImage>>();
When you get the callback in the Activity add the reference to imageRefMap. We can get the bimap from the CloseableReference. Next time you can check if the CloseableReference is present for a URL in imageRefMap, if present you can get the bitmap, no need to send the request down the pipeline again. This is mostly useful in case of Bitmap being used in RecyclerView or ViewPager.
Bitmap can be read from CloseableReference like below
Don’t forget to close the references in onDestroy of the activity so that bitmaps can be garbage collected.
Adding to Cache Manually
Fresco doesn’t have an in build function to explicitly add a bitmap into cache. The below code can be used to do so
Checking in Disk Cache Synchronously
In Fresco Disk cache check is asynchronous (http://frescolib.org/docs/caching.html#checking-to-see-if-an-item-is-in-cache). This is because Disk cache check is a costly operation and takes a lot of clock cycles, so the thread gets blocked. But if you are checking in Disk cache in non UI thread you can use this code
Reading from Cache synchronously without attaching a request to a DraweeView
As explained a request has to be attached to a DraweeView to load image from cache or network. You can use this code to get InputStream from Fresco Pipeline (Byte Array can also be read by small change to below code). Bitmap can be created using this. This should be used only if you need it in some rare cases.
Fresco has a very active community using it and backed by Facebook. More enhancements can be expected by the actively contributing community in the coming days.
Hope this was use useful!