This text is contributed by Karlo Karagic, Senior Android Developer at ITMAGINATION.
This list of categories and libraries is not exclusive, there are always some great tools available that flew under the radar (or we just missed them). This blog post is meant to give a good high-level overview of what’s out there.
This blog post will be split into logical sections based on potential app functionalities, for example, dependency injection, networking and persistence. In each of these sections, we will try to list every tool/library which makes sense there. And finally, we’ll try to make a conclusion for the given section and give a rough idea of when (and in which case) to use each of the listed tools.
By using the tools we recommend in this post, you will be able to build a solid app.
The most well-known library for dependency injection (shortened to DI) in the Android ecosystem. It's a compile-time DI framework which does come with some compilation time overhead but gives you runtime safety - if it builds it will work.
Once set up it's a phenomenal tool but setting it up can get tricky, especially in larger multi-module projects. Debugging is also worth mentioning here as it is challenging. Stack traces are cryptic, and you need to have some experience with the library to understand it.
Starting out is tough, since the documentation and tutorials are meme-level bad.
Built on top of dagger2 with the goal of reducing set-up boilerplate. This makes it a lot easier to use and implement than Dagger while losing none of the power. Only in specific edge cases, it would be easier to use Dagger.
This is a Kotlin DI framework which does things a bit differently. The basic idea is the same, but dependencies are not being generated during compilation but at runtime, instead (service locator). This means the library will not up your build time, but it does come with some overhead in runtime, and you lose your runtime safety (the library can crash your app with a missing dependency exception). The upside is it is ridiculously easy to use and set up and the documentation is quite easy to read.
It works really similarly to Koin but a bit worse. It is a bit more complicated and slower than Koin without providing any added benefits.
If you prefer compile-time generation of dependencies you should go for Hilt, it will be better in 99% of cases. Alternatively, if you are ok with run-time generation go for Koin, it is better in every way than Kodein. You can’t go wrong with going with either of these.
The only thing that comes to mind is if your compilation is taking too long. Switching over to Koin can help you a lot; there will be no code generation on builds, and it potentially opens you to using Kotlin Symbol Processing (KSP) instead of Kotlin Annotation Processing Tool (KAPT) which can bring a signification performance boost. This is a topic in itself but you can read some more info here.
It is an efficient HTTP client for underlying HTTP transport which includes caching, response and request manipulation and stuff like that. Retrofit uses it under the hood if available. You can of course use it alone, but you are missing out on some of the features that will make your life easier, such as URL generation and integrated JSON parsing.
There are probably no Android developers who haven’t heard of or used Retrofit. It is the de facto standard for networking on the Android platform. It is a type-safe HTTP client for Android. It’s a bit more high-level than OkHttp and handles areas such as URLs, requests, synchronization, threading etc.
Volley was widely used in the past but has since lost a lot of ground to Retrofit. It is still a viable choice today in some cases but for most uses Retrofit is a better tool. We know popularity doesn’t equate to quality, but Volley is much less popular with 3k GitHub stars compared to Retrofits 40k.
This is an interesting solution. It doesn’t improve much on Retrofit at first glance as it pretty much has feature parity with the only difference being it's written in Kotlin.
There are 2 added benefits. Ktor Client (as the name suggests) also has a backend counterpart which can provide certain synergies. The biggest advantage is its use in a shared codebase with Kotlin Multiplatform Mobile and as such, it can use the same code for Android and iOS.
Self-advertised as “The easiest HTTP networking library for Kotlin/Android”. It is Kotlin first and is written in a more functional style. It does not want to be compared to Retrofit as it provides a simpler and different experience.
Starting out with it will be a breeze, since it has an almost non-existent learning curve.
If you are not sure what to use, use Retrofit. If you are aiming for developing on multiple platforms, use Ktor. If you want to try something new or build a small project, Fuel is the way to go. Not much more left to say.
These libraries help us take a better look at what is happening with our network requests. They are a must-have if you want to debug your code within any reasonable time frame.
A logging interceptor comes with OkHttp and it is easiest to set up. Just add it to your Retrofit client and you are mostly done. Now you can see your requests and responses in your terminal. Since it’s not a GUI tool, it does take some scrolling up and down.
Chuck and Chucker are the same libraries where the former is used for Android apps which use OkHttp 3 and API <21 while the latter works with OkHttp 4 and later versions of Android.
This one is a tool you’d only use in specific times. While the other two mentioned interceptors are very easy to set up, Charles requires some manual work. It is still not as bad as it used to be; it was way harder in the past. What bothers some with Charles is that it tends to just stop working after some time for any number of reasons - but your mileage may vary.
Most importantly, however, it can intercept ANY request made on your phone. For example, if you are using some kind of 3rd party library to do something and you are having issues with implementing it, Charles can help you see under the hood what requests are being made by the said library (and where is it failing). Without it, you are pretty much blind.
All of these tools are very useful and all three can be used at the same time. It depends on how much detail you need. For basic requests, Logging Interceptors work just fine.
If you have huge response datasets, then maybe, you could use Chucker to gain more visibility, and in case you need to see everything that integrated 3rd party apps do, you need to use Charles.
We want to add an honourable mention here, mitmproxy. It is an open-source tools which works similarly to Charles. You can get more information here.
First of its kind, made in relatively distant 2008. You can still use it today, but it is showing its age. It is by far the slowest of all parsing libraries listed here, and, as it is written in Java, it is not null safe (fun fact, this was the inspiration for creating Moshi). Nevertheless, it’s great lib, easy to use and gets the job done.
First real competitor for Gson. It is written in Java, but it does have great support for Kotlin. It has many annotations to help you out. If used properly it is the fastest of the few although Moshi is not far behind.
Moshi is a library made by Square, the same company that brought us Retrofit, as well as some experts that worked on Gson. That should explain why Gson and Moshi are really similar. They are similar to such an extent that we would go as far as to considering Moshi Gson 2.0 (or 3.0). Moshi is a modern tool, and as such brings us a few benefits, primarily speed. It is also written in Kotlin, so it is null safe, and it doesn't rely on Kotlin Annotation Processing Tool anymore (even more speed if you are using Kotlin Symbol Processing in your app).
The newest kid on the block. There isn’t a ton of data available on its speed but what is there shows that it does not lag behind Jackson too much (or at all). This library is not made for Android specifically, as it was made for pure Kotlin such as Kotlin multiplatform. It is a bit less feature rich and stable than Moshi and Jackson, though, which will most definitely improve with time.
We recommend you use Moshi or Jackson as the safest choices, although Kotlinx serialization is a practical choice.
For multi-platform uses definitely pick Kotlinx Serialization as this is its main benefit.
Few words of caution: whatever you do, don’t pick Gson in new projects. It is past its prime and you should just go with Moshi instead as the transition to it is painless.
This is a battle-tested image processing library which has been with us for a very long time. Great speed, and tons of features, while being the fastest library out there. You can’t go wrong with choosing this one.
Just a small warning, it is using KAPT, so if you are planning to switch to KSP this could be a blocker for you.
Made by Facebook with the goal of implementing more advanced image transformations than in the case of Glide. Likewise, it has been with us for a long time as well. As a consequence, it is well tested and stable. It’s a bit less convenient to use than Glide but offers a few extra features. You can check some more details here.
Is only one of the listed libraries written in Kotlin with first-class support for coroutines. It is very fast with feature parity to others. One of the biggest benefits is that they had Jetpack Compose in mind during the development, so picking Coil should be a very smart choice for futureproofing your app. It is still relatively new so we can say that it is a slightly riskier option out of of the three.
If you are not new to Android development, you are probably using an Image processing library and probably one of these three (if you are really not new in the Android world then maybe even Picasso). If so, you might not have a reason to switch.
For new projects and projects that will be refactored/switched to Kotlin, we would go with Coil. It's the modern Kotlin library with first-class support for Coroutines and Compose and it has the potential to become a de-facto standard on Android. Please check if you will be missing some special features that Glide or Fresco could provide. For all other applications, Coil will just work.
Pretty much the default solution (if you are not using SQLite) for a local DB as it has Google's support. It's a well-known solution that has been used for ages in the Android ecosystem. It does a lot for you (maybe too much some would say). It simplifies data manipulation a lot, it works with both RxJava and Coroutines and is battle-tested. A great default solution.
The main difference here is that Realm uses a NoSQL solution and as such it will use far more memory than the other two. It asks a bit more from you as a developer but the main benefit you are getting is the blazing fast speed of queries. In fact, it’s as much as 10 times faster than Room.
Using this library comes a lot closer to vanilla SQLite than the other two. It performs on fewer abstractions and as such asks you to write SQL queries. Some will say this is a good thing (less is more), as it doesn’t hide so much of the implementation as Room does. Also, based on this article it is a lot faster than Room as well. The bonus benefit is it will work with KMM so you can share the code with IOS implementation as well.
If you are unsure what to go for, go for Room. It is supported by Google, battle-tested and safe with tons of resources online. Realm, on the other hand, is situational and you should discuss with your team if it is the lib for you. As far as SQLDelight goes, if you are looking for a multi-platform solution and you are not afraid of a little bit of SQLite queries in your code this is the lib for you.
You might be wondering why we split the local DB section from the persistence section? Slightly controversially, perhaps, we would say these two serve completely different purposes and as such should be separate, even though they can be used interchangeably. We’d say that almost any app has some persisted data that does not take too much space up. Using a full-blown DB would be a serious overkill. In these cases, we are presented with two options.
This is a vanilla solution provided to us by the android ecosystem. There is no need for any added libs or anything special. It has served us for a long time, and it just works but it has many drawbacks. It is not safe to call on the UI thread (could cause application not responding error - ANR), it has possible runtime exceptions and no type safety. Also, our humble opinion, the API does not look really nice but that can be improved upon - see this blog post.
This lib, which is a part of Jetpack Compose, solves all of the mentioned issues and also brings some added features. For example, it exposes data as a Flow which can play nicely with your other reactive code. It is stable for 1 year now, and should be safe to use. One downside to this library is the lack of a built-in encryption. You can always provide your own but that is a potential overhead as a source of tech debt and bugs.
DataStore is a better solution by a long margin, but sometimes, sub-par solutions are good enough (maybe you have just a few strings to save in the whole app). Also, if data encryption is important in your app you should go for Shared Preferences which come bundled with EncryptedSharedPreferences. It is up to you to decide what is important in your project. Details of these types of solutions are out of the scope of this blog but we think you can get a great overview here.
This section is also a bit specific. Android can be run on thousands of types of devices and as such, we can't guarantee that the device is fast and modern. This means, that we, the developers have to optimize our apps for as many devices as possible. Lists are especially heavy for rendering (and they get heavier with more complex items). For that purpose Android team gave us RecyclerView. We will talk about tools that abstract over or replace it completely.
This is the most sophisticated solution for this particular problem and more. It can help a lot with handling really complex lists and screens. On top of that, with Epoxy, you can pretty much make any screen into a RecyclerView. This will mean you can reuse elements through the app in an optimal manner. See Atomic design for inspiration. Epoxy is an extremely potent tool, but it will take you some time to get used to the code and the concept.
This is more specifically made for rendering lists of complex views. It helps a lot with abstraction over ViewHolders and diff utils. It is a very simple and flexible tool useful if you are having issues with dropping frames in your app. This lib is pretty easy to migrate to and can help you out really fast.
This is part of the Compose API and is not available if you are not using Compose. In case you are, this one is the simplest tool to use while being very powerful. Since this is replacing RecyclerView completely it cant work with Epoxy or Groupie.
RecyclerView is a very good and optimized tool but not the easiest to use. It is still a viable option and the other three solutions are very situational. In this case, we will not give any recommendation. Every project is different and has different needs and you will have to weigh the pros and cons of each of the solutions. But to not leave you hanging completely - Groupie is easy to learn and implement and can help you really fast (migration can be done in a few days in many cases).
This section is more of a talk about tool families for a reactive paradigm than to talk about a specific library.
RxJava, RxAndroid, RxKotlin, or simply RxJava, is a well-known, widely used family of reactive libraries. It has a very powerful and a complete API for creating and consuming reactive elements. This also comes at a cost; the extensibility of RxJava makes it really hard to learn and especially to master. Even though it is written in Java and is really old it is still used and loved to this day. It is definitely a practical choice even for completely new apps.
A new kid on the block. Fun fact: if you import Coroutines in your app, Flow comes with it. The key difference between Flow and Coroutines, is that the former may return many values, while the latter will always return just one. It is much simpler than RxJava and if you know Coroutines it is a breeze to learn (although it will take some time to master). A great benefit is that it can be used with RxJava (it's interoperable) and is a bit faster. The downside would be its young age, at least compared to RxJava. It hit its 1.0 version not so long ago.
The verdict is difficult to come to. Both of these tools are great, and if you haven’t tried reactive programming please give it a go - you will most certainly like it. Choice of these tools should mostly rest on the knowledge base you have in your team. If you have experienced RxJava devs there is no benefit to switching to Flow (maybe simpler and more concise syntax). The biggest issue for RxJava is the steep learning curve and as such, we think it will be easier to find good Kotlin/Coroutines/Flow developers in the future and that could be an important factor for you.
There is also an angle which says that for very complex projects RxJava is a preferred tool with its comprehensive APIs – we aren’t so sure.
Keep in mind that these can work interchangeably, and this does not have to be an all-in decision. You could for example make new features in Flow while still maintaining RxJava code (I did this on one project in the past it worked reasonably well). This could keep you stable and at the cutting edge at the same time.
Ktlint is easy to use and is a simple linter for Kotlin made by the Pinterest devs. It can also help with the formatting of our code. You can of course add custom rules or ignore some of the default ones. You can check out the specifics here.
Detekt is a bit different. It is a static code analysis tool for Kotlin. It is a bit harder to set up, but it is worth it. There are a lot of rules here as well and you may not want all of them at every moment, so the tool developers made it easy to turn off some of them. You can read up on it here.
This one is easy. You should include both of these tools in your app, and probably in your CI pipeline. The only time this may be overkill is if you are working alone and have a lot of experience writing quality code. We would like to add an honourable mention here – SonarQube. It is a huge tool, out of the scope of this blog, but you can find some more info here.
This will be a big section. There will be no conclusion part here as you can use as many or as few of recommended tools from here as you want. They are all useful for certain use cases and situations.
If you do not know what a memory leak is - you definitely need this tool and you need to read this article. Even if you do know, what it is, you should still use it. Why? Well, there are quite a few situations where you can cause memory leaks without knowing it (for example not disposing of disposables in RxJava, which is easy to do). On better devices with lots of memory, you will often not even notice you made a mistake, but on anything slower than a mid-level device, you are causing a bad user experience.
This tool is here to catch memory leaks and inform you immediately exactly where are they occurring. Most often it has something to do with RecyclerView and/or RxJava, but not always.
Stay wary of memory leaks!
In modern times we got bored with spinners and progress bars so the people from Facebook brought us Shimmer. It is a special effect which mimics light bouncing off your view indicating that loading the view is in progress. It's simple to include and works great out of the box if you need something like it – you just add it as a wrapper to your views. More info is available here.
If you need custom animations, you need this tool. Brought to us by Airbnb developers, this is an Adobe After Effects animation parser. It has a very clear and concise API while producing phenomenal results. You can see some of the examples here.
This is just a small API built on top of the Androids Log class which can save us the pain of doing this stuff every time we make a new project. Essentially, it removes the need for tags, handles release and debug logging in a simple manner and adds customizable meta-data for logs. Not a must-have but a great, small and quality of life improving lib. There is also some cool stuff you can do with Crashlytics as well – see this article.
It's a tool to help find and fix stability issues as fast as possible (reports are available almost in real-time). As much as you test your app, you can’t cover all the Android devices (there are way more than 10.000 different models). This tool helps you catch those pesky instabilities before they become bad Google play scores/reviews.
If you want to track a bit more than just crashes this is a really valuable tool. Not to get into too much detail, GA can help you with knowing how the user interacts with your app. Maybe it will help you perfect some of the flows or help you trim the features users don’t need/want. In any case, with this tool, you are not flying blind.
Hopefully, this overview will help you in your future projects. Like we said in the beginning, there is a huge number of interesting and useful tools available, and it is unreasonable (and impossible) to cover them all. But this list should be a great starting point as most of these can be seen in many projects we have worked on.