Extending Picasso’s RequestHandler to handle non blocking calls


The project I was working on had complicated image handling logic for loading images. This was due to the image coming from a websocket connection. The existing image handling only supported nonblocking handling. As my plan was to create a custom RequestHandler and add it to Picasso via the addRequestHandler method this presented a problem. I first found this very useful writeup on how to make a custom RequestHandler. I soon realized I had a problem, the RequestHandler was expecting the Result object(that contained the image I was downloading) to be synchronous call, as in a blocking call. As websockets wouldn’t be immediately returning a response, this was no bueno. Fortunately the websocket request had a callback notifying me when the request was completed. I first tried googling for converting async callback to sync callback which didn’t yield anything useful. So I changed up the search terms to non blocking callback to blocking callback. This fortunately yielded a stack overflow response that had just what I was looking for. CountDownLatch.

How CountDownLatch works
CountDownLatch takes an integer value to start with. Then when one of the await methods is called that thread blocks until sufficient number of countDown request have caused CountDownLatch to be 0 or less. This was perfect. Or nearly so. I was worried about the side effects of what would happen if the callback never happened. Fortunately the CountDownLatch class has two await methods. The first await that takes no parameters will wait forever. The second await takes a long, and a TimeUnit. It behaves much like the first except that it throws an InterruptedException when the time has exceeded what was passed in.

My short term solution until the websocket handling can be refactored is to set a CountDownLatch to execute the request, then wait for it to complete or timeout trying. I then check to see if the image was added to my cache and then return either a successful Result object or null if the request failed for some reason.

public class DemoRequestHandler extends RequestHandler {


        public boolean canHandleRequest(Request data){
               // some logic to verify that this request handler can handle this request
               // usually involves comparing the data.uri contens
        }

        public Result load(Request request, int networkPolicy) throws IOException{
                final CounDownLatch latch = new CountDownLatch(1);
                // do some async downloading logic here, on success store image in cache that will call latch.countDown()
                latch.await(15, TimeUnit.Seconds);
           
                // check if image is now in the cache
                if(image is in cache){
                      return new Result(image, fromCache);
                }
                // uh oh image wasn't in cache, take a look at the base RequestHandler for retry logic
                return null;
        }
}

Leave a Reply

Your email address will not be published. Required fields are marked *