Quite recently, we added a sync feature to Any.DO. The users can sync all their tasks to Any.DO’s server, allowing them to access their tasks from our Android, iOS and Chrome clients.
Our data structure is a classic fit to REST API architecture. After getting our server ready, it was now the time to teach the Android client how to “talk the talk”. I didn’t want to use simple HTTP requests, constructed to use our REST API. I wanted to use some library to make my life easy, and my code readable. I also didn’t want to reinvent the wheel, so I did my research. I found some good and simple libraries for Android, as Resty, but then I found a more elegant solution for that – RestAdapter in Retrofit by Square.
Using RestAdapter, I can easily create a Java API to represent my REST API. The HTTP request is done in a background thread, and the result is returned as a callback. No need to open my own thread for the network operation, everything is done for me! Here’s an example for a simple service:
This is an example for getting all the friends in a shared task. I declare an interface for my API with the name of the service I’m providing, and for each API call I declare a method. For each method I set the HTTP request type (GET/PUT/POST/DELETE) and the REST API URL. The URL in this case is tasks//friends. The taskId is the first parameter in the method, and matching it with the parameter {taskId} in the URL is done using the “@Named” annotation. The Callback is called when the API call has returned, with the object I’m requesting. The object is constructed from a JSON string (other type handlers, as XMLs, can be added), and the parsing is done by the library all by itself, the developer doesn’t have to deal with JSON parsing at all, he sends an object, and gets an object!
This library was built for general Java use, and it’s using Google’s Guice to set objects in the code. In Android we can use RoboGuice to get this done. Now, to use our interface, I need to declare it as one of my data members on my class, and use the @Inject annotation, get it all “Guiced” up with some magic implementation (we’ll get to that later).
Later on, I just call the method I want for any specific use
The callback is an interface I need to implement, telling what I need to do in case of a server error (HTTP response > 500) or client error ( > 400) or in case of a success, where I get the object I requested. A typical call will be:
This is cool, since I don’t even have to compare HTTP status codes, I get a clean callback for each case.
HOWEVER,
If I want to call several API calls, one after another, from a background thread, it’ll get messy. For example, the tasks sync algorithm: getting all the categories, and all the tasks, merge with local changes and then update the server. We have at least 4 network calls. Since this entire routine runs in a background thread, there’s no use for the callback system, I don’t care if each call will block the thread, It’s not blocking the user’s UI. I also have to wait for each command to finish, before executing the next one. Let’s see how it looks like:
Pretty cumbersome, right?
That’s why I decided to solve this problem by allowing to run it, including the network call, in the current thread. It’s up to the developer to decide whether he wants his API call to run asynchronously, or to be blocking. His intention will be declared in his method declaration. As an example, let’s take the “getFriends()” method, and create a blocking version of it:
The synchronous method returns the object we seek for, the Friends object, and does not receive any Callback. All that looks great, but how to make it work in the existing library?
Before I could explain the modifications I did to the library, I need to explain how it works. Since Square did a pretty good job making the code well generic, I’ll simplify the code a little to make it easier to explain.
Remember the “magic implementation” for the API’s Java interface we created? Since we’re declaring an interface with no implementing class – how does it know what to do? For that, we’ll get a close encounter with one of Java’s magical creatures – Proxy. The Proxy class is basically a runtime implementation for interfaces. When we declare a Proxy, we set the interface(s) we want to implement and an InvocationHandler class, to bring this interface into life. Let’s see how it looks:
We took our own TaskService interface from before, and created a Proxy for it using the newProxyInstance static method. We pass the ClassLoader and the Interface class itself. The handler is the last and most important argument here. Let’s take a look at the handler’s implementation:
The InvocationHandler is implementing a single method – invoke(). It provides us the method we called on the interface (e.g. “getFriends”) and the arguments we passed to that method (e.g. “taskId” and the Callback object). We build the Http URI request using that data:
-
method – We access its annotations to get the HTTP method (GET/POST…) and the REST URI (e.g. “tasks/{taskId}/friends”)
-
args – Containing the parameters/objects to send with the request, as taskId itself.
The HTTP URI Request builder’s job is making this:
into an appropriate HTTP request as “http:///tasks/4354/friends”.
Hooray!
(That’s what Festivus is all about…)
The next few lines is where I added my code, to support running the request on the foreground. I check if the last argument is a Callback object. if not – I run the request on the foreground. Simple as that. Notice that I return the value I get from foregroundInvoke(), because that’ll be the object I’ll return for calling this method, in this case – a “Friends” object. Other methods are using callbacks, that’s why they return nothing.
All of this looks so nice, but what about error handling?
We want to believe the world is safe – peace in the middle east and HTTP status code in the 200 area. Unfortunately, things are more complex. Errors will always be around and we need to take care of them. What should we do in case the taskId wasn’t found? The server will return 404, but since we have no Callback object, we need to give some feedback to the program using this adapter. In this case – we’ll throw an Exception.
I built a ResponseNotOkException, to be thrown when we get a status code not in the 200-299 zone. Let’s review the foregroundInvoke():
In this method, we parse the response from the server, which is in a JSON format, and create an object from its JSON representation. Notice the object type is taken from the Method’s return type attribute, that’s another use in the Method object we got in the invoke() method presented earlier. In case the status code is not in the “OK range”, we create a ResponseNotOkException, and optionally fill it with data from the server (could help the client get more info on the problem). To get our code compatible with Exceptions being thrown at him, we need to declare it in our interface’s method. The Final interface will look like:
A usage example will be
Phew.. That was quite a journey. Now we know more about how to use Proxies and manipulate them to solve our problems. The code I presented here was reduced and simplified. To see the full source code, you can access it here:
https://github.com/Udinic/retrofit
Hopefully it’ll get approved by square, and added to the main repository.
If you want to learn more about the Retrofit library from Square, you can check out this talk by 2 of their top Java/Android developers here.