Hey, as 2021 developers we have a lot of options to execute simple tasks. Hundreds of amazing open source libraries are available on GitHub, allowing us as developers write less code.
But there is a downside of it, very often developers (such as myself) do not understand how these libraries are working internally.
This article goal is to show how such simple procedure as image downloading into ImageView can be done using only Android SDK and pure Threads (once i was asked exact same question on one of interview). So let’s start.
As an example we will implement simple app that has one screen with list of images and theirs titles.
1. Let’s determine API for our download service. It seems like for the first implementation we will need only target ImageView and image url itself
2. On android we cannot execute network requests on main thread, so we will need to execute our image downloading part in some other thread. But in case of images inside of recycler view we might need to download multiple images in parallel, so we will need to somehow manage all this threads created by ourselves to reuse them when image downloading is finished. Fortunately JDK already have similar mechanism called ExecutorService. ExecutorService allows us to execute Runnables and internally it manages all thread creation and reusing for us.
As we don’t know exact amount of images need to be downloaded simultaneously best choice will be CachedThreadPool Executor Service, as it creates new thread as needed, and reuses threads that already finished its work, which can be created using factory method of Executors class.
3. Then we need to download image from URL. In this case JDK also rescues us offering HttpURLConnection class. When we establish connection to specific URL, we can get an input stream and convert it to bitmap. So our image downloading part will look like this.
But actually we don’t need a full downloaded bitmap, because on screen we are showing only thumbnails.
4. Using this function we finally can write our Runnable
So… let’s try to execute this one, and see the result
And it’s working… kinda… images for some reason randomly changing… let’s try to fix a few issues.
First of all we need to remember that android views are not thread safe. And better option is not to set bitmap directly from download thread, but to use Handler. What Handler does is just adds messages to MessageQueue of associated Looper, and then executes them. Each view already has it’s own handler, so let’s use that.
Another thing we need to cover is case when we don’t need to set bitmap into image view anymore. For example if we scrolled out cell with image out of the screen. For this case android provides us with OnAttachStateChangeListener which tells us when view is attached/detached from window. And also we need to refresh current bitmap (if loaded).
And last thing, we can implement simple caching of loaded bitmaps not to load them again. As we downloading them in different threads let’s use ConcurrentHashMap for it.
Of course, this is not a perfect solution, but one of the many approaches to solve this problem. If you have something to add to this, pull request will be highly appriciated. All code is available on GitHub. Hope you enjoyed reading it. Cheers!