Hackernoon logoLoading and Caching Images with Just One Annotation in Android by@crypticminds

Loading and Caching Images with Just One Annotation in Android

When we are developing an android application it is common to come across a situation where we want to show an image somewhere in the app.The easiest way to handle this is to bundle the image along with the app but the downside to it would be increasing the size of the app. It is not feasible if the application needs to display a lot of high resolution images.So, the next best thing is to host the image in some server and download it from there when the app starts. This is where image caching plays a very important role. We download the image once and store it in our cache and reuse it whenever required. This post will show how we can do that using just one annotation using the ColdStorage library.

Introducing @LoadImage annotation

Before speaking about the usage, let us look at a sample code that loads an image into an ImageView from a URL.
@LoadImage(
        R.id.image_1,
        "https://images.unsplash.com/photo-1549740425-5e9ed4d8cd34?ixlib=rb-1.2.1&w=1000&q=80",
        placeHolder = R.drawable.loading, enableLoadingAnimation = true
    )
    lateinit var imageWithAnimation: ImageView
Clean and simple isn't it ?

What just happened ?

Now let us break down what we exactly did with the annotation :-
  • We passed the resource id of the ImageView (R.id.image_1) that we want to bind to the variable imageWithAnnotation .
  • Next we passed the URL from which the image needs to be downloaded.
  • We passed a value for placeHolder and enabled loading animation. I will talk about them a little bit later in this post.
There is just one task left before the annotation performs it's magic , we need to bind the class where the annotated ImageView is present to the cache. Assuming that the annotated view is present in an activity , we will bind the activity to the cache using the Cache.bind method. It is important to note that the binding should only be done after setContentView .
 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.load_image_example)
        Cache.bind(this)
    }
The annotation works in activities , fragments and custom view.
The annotation will take care of binding the view to the variable , displaying the place holder image , downloading the image and once the download is complete replacing the placeholder image with the downloaded one.

Place holder image and animation

We do not want to show a blank white section when the image is downloading right ? We want out app to be fancy and that is why we will use the placeholder image and enable an animation to so that the user can feast their eyes on it until they are even more mesmerized with the image after the download completes.
The placeHolder parameter expects a drawable resource that will be displayed in place of the actual image. By default there is no animation enabled but you can set the enableLoadingAnimation to true to rotate the placeholder image.
(At the time of writing, only the rotation animation is supported but custom animations are one of the upcoming features of the cold storage library)
Demo of placeholder image with animation enabled :-

Meh, this is not impressive at all....

Alright then, I will try to convince you with a powerful feature of this annotation.You can store the downloaded image into the internal storage so that when the app starts next, the images will be loaded into the application memory from the device storage. Don't worry you have perfect control over the number of days an image stays in the storage after which ColdStorage will automatically remove it.
Simply pass "persistImageToDisk = true" to the annotation to store downloaded images into the memory.
@LoadImage(
        R.id.image_1,
        "https://images.unsplash.com/photo-1549740425-5e9ed4d8cd34?ixlib=rb-1.2.1&w=1000&q=80",
   persistImageToDisk = true
    )
    lateinit var imageWithAnimation: ImageView

What if my image view is inside another View and I can't annotate it directly :(

So you created a reusable view or layout and cannot directly annotate the ImageView inside it ? Hmm...... No problem.
Use the @Parent annotation along with the @LoadImage annotation.
@Parent(R.id.my_custom_view_1)
@LoadImage(R.id.my_nested_image,"my_url")
lateint var innerImageView : ImageView
Now the ImageView inside the view with id my_custom_view can be accessed by @LoadImage.
Your code is now so much cleaner and maintainable compared to this ->
val myCustomView : MyCustomView = findViewById(R.id.my_custom_view)
val myImageView : ImageView = myCustomView.findViewById(R.id.image_view_inside_custom_view)
// multiple lines of code for downloading and adding the bitmap into the ImageView

Conclusion

Caching should be completely abstracted from the application logic and @LoadImage does exactly that. It does all the heavy lifting for you so that you can focus on creating great applications by just focusing on the application logic.
Check out the ColdStorage library :- https://github.com/crypticminds/ColdStorage. it has several other features that you might like. Join the stargazers if you like the library :)
Previosuly published at https://medium.com/@crypticmindscom_5258/caching-made-easy-on-android-with-kotlin-part-4-18e7b066e9c2

Tags

The Noonification banner

Subscribe to get your daily round-up of top tech stories!