Back to the basics: Android with no libraries (Part 1)

Gabriel Sanmartín
5 min readMay 14, 2020

--

Earlier this year I applied for a job at some big tech company whose name I’d rather omit.

Their process was fairly typical: a live Data Structures/Algorithm code test with one of their engineers, then an assignment, then visit to their HQ, then potential offer.

After some preparation I got through the live coding test and passed, so they sent me an assignment.

Now having been on the recruiting side myself for a number of companies in the past, and also with the experience of being the candidate in a few instances, I am somehow used to seeing multiple assignments. Most of the time they involve pretty much the same requirements: consume an API endpoint and present it on the screen, generally under a master/detail flow.

This case wasn’t the exception: it required the candidate to consume flickr’s API for photo search and present the images on the screen with an endless scroll. However, it came with a quirk: the requirements specified that the use of third party libraries wasn’t allowed.

Flickr’s API for photo search

https://api.flickr.com/services/rest?method=flickr.photos.search&format=json&nojsoncallback=1
Example JSON Response

While that might sound scary, I decided to devote the following weekend to the task and try and go back into the basics. After all, while we take for granted all those nice libraries that form the tech stack standard on any platform, any good engineer should be able to do it from scratch, right?

My approach was the following: I would start by quickly producing an app using my library stack of choice, which took me around an hour, then remove each library one by one until I was left with just LiveData and Material Components. My reasoning is that this way at least I would start with something that worked, then do as much as I could without libs and deliver whatever result that I could reach and still worked.

Also, in this way I could unit test my way into the different steps to make sure everything worked.

Note that obviously the solution presented here will not be nearly as powerful as any of the libraries it is replacing. It will be taking shortcuts and ad hoc solutions, and thus the code we will produce will in no way be nowhere near production ready. It is, however, a good exercise to cover the basics of an app and understand a little better all the heavy lifting these libraries do for us behind the scenes.

So let’s go into this first implementation.

Step 0: Starting with libraries

I went for a pretty standard stack on modern Android development:

  • MVVM architecture using LiveData for ViewModel/UI single direction communication
  • Glide for background image fetching
  • Retrofit for API consumption
  • GSON for (de)serializing responses
  • RxJava2 for background threading, request transformation and communication between domain layer and ViewModel

In the end, this is what my build.gradle looked like:

Dependencies for step 0

I intentionally omitted any Dependency Injection library for simplicity. After all my intention was to replace it anyway and for such small assignment I deemed that to be a bit of overkill. In return, what I did is just set up a ServiceLocator for Singleton dependency definition and Inversion of Control, which was kept through all iterations of the project:

ServiceLocator.kt

Other than that, this first approach is pretty straightforward and I will not go too much into detail, since there are a thousand articles on how to build an app with this tech stack.

You can check the implementation, though, over at this branch

Step 1: Removing Retrofit

Let’s start off with the end of the chain, and arguably the easiest: removing the API consumption library.

With Retrofit, this basically means reimplementing the interface we defined in the previous step:

interface FlickrService {

fun getSearch(
@Query("api_key")
apiKey: String,
@Query("text")
term: String
) : Single<ApiResponse>
}

Note that Retrofit is a general purpose REST library that supports all HTTP methods, multiple headers and multiple mappers to convert our responses into something with more semantic value. It works by using reflection to implement what we declare in our interface using an HttpClient (that we can specify) and the Adapters we indicate (to transform the format of our responses).

Obviously we are not gonna reinvent the wheel here, so we will make our implementation a little bit more ad hoc for what we need. That is, we will only implement the minimum to make our getSearch method do what Retrofit was secretly doing for us.

That means we will create our own HttpClient so that it performs a get request provided with a URL and return a String with the response:

HttpClient.kt

We make use of HttpUrlConnection directly to perform a request against our backend, by specifying the URL and the “GET” method directly. Then we just convert our response into a String using a BufferedReader. Pretty stantard Java!

Request into a String

So our Search method can just call this client like so:

SearchRequest.kt

But wait! We still have RxJava2 as our background processing provider, so we somehow need to convert this into an observable class from Rx. This is easily done by using the fromCallable factory method on the Single object:

Search into Rx

And that’s our first step! Pretty straightforward huh? With this, our dependencies section now looks like this:

Dependencies for step 1

Check this implementation over at this branch

Step 2: Removing GSON

Now we have removed our REST client to replace it with our own, but we are still relying on our serializer to transform the responses into our value objects.

Gson also uses reflection to transform the strings responses coming from the backend into objects, by the use of annotations. As we did with Retrofit, we will not be reinventing the wheel but producing an adhoc implementation to cover our scenario.

In the previous step we abstracted the deserialization by creating an interface like so:

interface Serializer {

fun deserialize(json: String) : ApiResponse
}

Which we implemented with GSON by passing in our GSON instance (already in use in our library filled approach):

GsonDeserializer.kt

So to replace GSON we will simply create our own implementation of the Serializer interface.

The Flickr Api endpoint responses looks like this:

Example response

Which we modelled like this:

Model classes

Se we need to make sure we transform our json string into those objects. Working with raw JSON is simple enough, we can just create a JSONObject by passing in our original response string, then iterate through it by getting simple types (Int, String, Double…), other JSONObjects, or JSONArrays:

Custom deserializer

And we are done! Again, in a real world environment we would have to create some flexible solution so every time the json changes we don’t need to change our mapper. Gson (or moshi) does this for us by using reflection to call the getters/setters named after the different fields.*

*moshi can also generate code for faster runtime (albeit slower compilation time)

One dependency less makes our build.gradle look like this now:

Dependencies for step 2

I’ve made the source available for this part of the process at this branch

Next up… Glide and RxJava!

--

--