Mobile14 minute read

An Overly Thorough Guide to Underused Android Libraries

Any experienced developer will tell you that their best code isn’t code they wrote. It’s code they took from someone else’s work. Many of the problems we encounter have already been solved—and the remedies packaged into libraries available to anyone. Why reinvent the wheel when free wheels are everywhere?

In this guide, Senior Android Engineer Gilad Haimov will take you on a quick tour of some the most powerful Android libraries out there. Robust as a hammer, faster than a drill, and more precise than any scalpel; no Android developer should leave home without these must-have tools.


Toptalauthors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.

Any experienced developer will tell you that their best code isn’t code they wrote. It’s code they took from someone else’s work. Many of the problems we encounter have already been solved—and the remedies packaged into libraries available to anyone. Why reinvent the wheel when free wheels are everywhere?

In this guide, Senior Android Engineer Gilad Haimov will take you on a quick tour of some the most powerful Android libraries out there. Robust as a hammer, faster than a drill, and more precise than any scalpel; no Android developer should leave home without these must-have tools.


Toptalauthors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.
Gilad Haimov
Verified Expert in Engineering

Gilad has years of experience in developing Android applications, server-side programs, and communication systems.

PREVIOUSLY AT

bmc Software
Share

Any experienced developer will tell you that their best code isn’t code they wrote. It’s code they took from someone else’s work.

Yes, we developers are innovative problem-solvers, but many of the problems we encounter have already been solved—and the remedies packaged into libraries available to anyone. Why reinvent the wheel when free wheels are everywhere?

Android is no exception. The ultimate source for code reuse is the Android SDK itself, which comes with great constructs and services that will do a lot of your work for you.

But where the SDK runs short, the Android community has created some top-of-the-line libraries that can save you tons of coding work, replacing it with highly tuned, vetted, and tested implementations. I’m not talking about the obvious libraries—Android Support Library, Android Design Support Library, Gson. I’m referring to tools you may not know about. And even if you do, you’re probably not using them yet.

One of the major differences between a standard and master developer is the correct use of third-party libraries. A master developer will roughly accomplish the same task three times faster than a novice, and usually with shorter code. A good deal of this comes from knowing which third-party libraries to use and how to correctly embed them within your project.

I’ve been developing, mentoring, and leading Android teams for years, and I’ve studied and used dozens of external tools and libraries. (I’ve even been known to read their implementation code and discuss their internals with the developer.) Many have been highly effective in helping me get the job done, but the truth is, most were not.

That’s why I’ve put this guide together. Lean on my experience, as well as that of other mobile developers, to make sure you’re using the best libraries. I’ve picked seven. I suspect they’ll be some of your favorites very soon too.

Selecting the Right Android Library

When choosing a library, I look for four key features:

  • It provides a consistent and high-quality solution for a real and non-trivial problem.
  • It uses as simple an API as possible.
  • It does not force any changes in my overall architecture.
  • It has a large user base and, preferably, an active developer community.

The first three features are deal-breakers. If they’re not present, I move on or start hand-coding.

Android Libraries

The libraries I cover below pass all four tests. They also solve some of the most challenging aspects of mobile development.

ButterKnife: The Ultimate Dependency Injection Tool

This is the ultimate dependency injection library for Android. Simple, robust, super fast (no reflection!), and capable of doing away with a lot of your app’s boilerplate code.

Some would argue that ButterKnife is what Android’s layout to Java mapping should have been in the first place.

Android Butterknife dependancy injection

Gone is the need to directly bind each of your views via a call to findViewById(); instead, there’s an annotated view that gives you direct access to code.ButterKnife also eliminates the need for boilerplate UI events such as onClick, onTouch, and so on, and replaces them with auto-injected code.

But enough chitchat, let’s see the code.

View field binding:

class MyButterKnifeActivity extends Activity {
  @BindView(R.id.name) TextView name;
 @BindView(R.id.address) TextView address;


  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.simple_activity);
    ButterKnife.bind(this);   // MUST BE CALLED BEFORE ACCESSING UI FIELDS
    name.setText(“etc etc”);
  }
}

Resource binding:

class ExampleActivity extends Activity {
  @BindString(R.string.username) String username;
  @BindDrawable(R.drawable.graphic) Drawable graphic;
  @BindColor(R.color.bg_color) int bgColor;
  @BindDimen(R.dimen.lower_padding) Float lowerPadding;
 
  // and no need for getResources().getString()/getDrawable/getColor()
}

UI event binding:

@OnClick(R.id.my_button)
public void clickHandler(View view) {
  // onClick logic goes here
}

AndroidAnnotations: Taking Dependency Injection to the Next Level

A close second to ButterKnife when it comes to dependency injection, AndroidAnnotations uses a slightly different approach: auto-generated classes, which, once you get the hang of them, are extremely simple. Even more useful is that it allows you “name-based” dependency injection. For example, @ViewById ListView myUserList; instructs the library to assign this field with a layoutListView by the same name.

AndroidAnnotations is also blazing fast, but it achieves that in a somewhat different manner than ButterKnife. Instead of runtime binding dependency injection, AndroidAnnotations creates a build time duplication of all affected activities and pushes its connection logic into them, thus allowing you to get the same performance you would with hand-coded logic.

But AndroidAnnotations’ injection capabilities go even further than that. You can inject both state and layout into an activity.

AndroidAnnotations implementation:

@NoTitle
@Fullscreen
@EActivity(R.layout.my_layout)
public class MyActivity extends Activity { 


    @ViewById
     ListView customerList;  // auto-binded to R.id.customerList


     @App
     MyApplication app; // auto-binded to app object
   
     @AminationRes
      Animation fadeoutAnimation; 


    @UiThread
     void updateUI() {
          // main thread action
     }


}

The last annotation requires a bit more explaining: A common task for a multi-threaded Android app is switching from background (or worker) threads to the forward (or main or UI) thread, which is the only one that allows access to UI components. This task, while not complex, is often required and involves some messy coding:

      new Handler(Looper.getMainLooper()).post(new Runnable() { logic goes here } );   // NO ANNOTATIONS

In AndroidAnnotations, all you need to do is annotate your function with @UiThread, and it’s now guaranteed to always execute:

          @UiThread void updateUI() {..}   // WITH ANNOTATIONS

Note that this annotation applies to standard Android component classes (activities, services, and so on). But what happens when I also want to annotate my own classes?

Here, AndroidAnnotations comes up with a new concept, that of the EBean. All you have to do is to mark your class as such using @EBean, and you’re good to go:

@EBean
public class MyNonComponentClass {


  @SystemService
  NotificationManager notifManager;


  @Bean
  MyOtherClass dependency;


  @UiThread
  void updateUI() {
        // main thread work goes here
  }
}

EventBus: Cross-Component Communication Made Easy

EventBus library turns a problem that’s haunted Android developers for years into a walk in the park. Cross-component communication has never been simpler—use a simple pub/sub model to communicate between any two parts of your system.

EventBus animation

Using the event bus will result in more robust code, as it forces you to decouple your components from one another.

Your background polling service no longer needs to be aware of your fragments to feed them with change events.

EventBus usage is straightforward.

a. Create event classes. Working with POJOs here is best:

           class NewUserEvent {
                  String fullname;
                  String address;
                  String role;
               
                 // add getters and setters 
           }

b. Create event handling methods in the class—any class that you wish to subscribe for these events:

         class MySubscriber { 


            @Subscribe
            public void newUserHandler(NewUserEvent event) {
                       // handle NewUserEvent
            }


            @Subscribe
            public void newUserHandler(AnotherEvent event) {
                       // handle AnotherEvent
            }
  }

But hey, any half-experienced Android developer would stop and ask at this point: What’s the threading model of these handlers? And can I force a handler to run off the main thread if, say, it involves UI component access? Good question…

By default, all handler methods run on a worker thread taken from a thread pool that’s allocated and maintained by EventBus itself. If you need a handler method to run on the main thread, expand your subscription annotations as follows:

                  @Subscribe(threadMode = ThreadMode.MAIN)
                  public void runOnMainThreadHandler(AnotherEvent event) { … }

Warning: Do not overuse this feature! Long-running operations should never be executed on the main thread, and even with quick operations, be careful. Overwhelming the main thread is the surest way to make your app slow, jumpy and basically less fun to your users.

c. Manage the EventBus registration lifecycle of your subscriber class—that is, when does it connect and when does it disconnect from the bus? A reasonable registration flow for an activity would be:

class MySubscriberActivity extends Activity { 


@Override
     public void onStart() {
         super.onStart();
         EventBus.getDefault().register(this); // START RECEIVING EVENTS HERE
    }
 
   @Override
    public void onStop() {
        EventBus.getDefault().unregister(this); // NO MORE EVENTS
        super.onStop();
    }
}

The above is, of course, just an example. You can perform the (un)registration anywhere you choose.

d. And finally, actually fire an event:

        EventBus.getDefault().post(new MyEvent(“I’m here”));

There’s a lot more to know about using EventBus: multicasting events (the default behavior), using sticky events, delivery threads, priorities, and more. But the above is enough for you to get started with this simple, yet powerful, technology.

OkHttp: Android's HttpClient on Steroids

This is the way Android’s HttpClient should have been written. Very simple, very smart. The OkHttp library internally takes care of the retry loop, payload auto compression, Http/2 support, connection pooling, and response caching so you can avoid unnecessary network access.

OkHttp library animation

OkHttp usage is a no-brainer.

Http POST:

     OkHttpClient client = new OkHttpClient();
     MediaType JSON = MediaType.parse("application/json; charset=utf-8");


     RequestBody body = RequestBody.create(JSON, json_str);
     Request request = new Request.Builder()
        .url(url)
        .post(body)
        .build();
    Response response = client.newCall(request).execute();
    return response.body().string();

Http GET:

      OkHttpClient client = new OkHttpClient();
      Request request = new Request.Builder()
            .url(urls[0])
            .build();
      Response responses = client.newCall(request).execute();
      String jsonData = responses.body().string();

OkHttp also supports such useful features as asynchronous networking, request redirect route query, local cache query, and more. Feel free to use them where needed. Most developers use OkHttp as a smarter replacement for Android’s default HTTP client, HttpURLConnection. In fact, this entire project started as a private fork for HttpURLConnection.

I love its robustness—it immediately adds to your network layer.

With just a few lines of code, OkHttp makes your app behave like you spent nights debugging and optimizing your network layer.

Picasso: There's a Good Reason Google Uses It Too!

Picasso is the simplest and most robust way of managing image download, caching, resizing, and cropping.

This statement:

         Picasso.with(context).load(url).resize(50,50).centerCrop().into(imageView)

Will do this for you:

  • Connect to a remote URL.
  • Download an image.
  • Store it in a local LRU cache which it will also manage for you.
  • Resize the original image before loading it into memory.
  • Run all of the above on a thread pool managed by Picasso.
  • Use the resized image to populate your imageView.
  • Before any future runs, check the local cache to ensure a network round trip is really necessary.

Building the above set of tasks would require many hours of work, even for a master developer. And that assumes you remembered everything. What if you forgot, say, the resize part?

Picasso Android library animation

Well, on the average Android device, an app gets no more than 50 to 60 Megabytes of RAM, and the pixels-to-bytes factor for most Android devices is 4. This means attempting to load a 13-megapixel image from the SD card would require 52 Megabytes of RAM. In other words, your app would immediately crash.

This is just one example of the strength of Picasso. One of the first things I do when optimizing/debugging a media-intensive legacy project is switch all image loading to Picasso. You’d be surprised the impact this one simple step has on app quality.

One of the strongest testaments to the power of this library: Many of Google’s own Android code samples from the past two years employ Picasso for image loading.

ActiveAndroid: ORM Sans Performance Overhead

ORM, short for object relational mapping, was made popular in the days of J2EE. It allows you to store your POJOs in, and retrieve them from, a database without having to convert them into separate fields.

ActiveAndroid ORM

Is it helpful? Very much so, as it allows you to write a large portion of your app without coding any SQL statement.

It’s also very efficient. In the old days, ORM platforms massively relied on reflection and were notorious for being slow. Modern platforms, including ActiveAndroid, are much faster and for most practical requirements, will not suffer from performance overheads over raw SQL coding.

No hand-coded SQL statements, no performance overhead!

Usage:

a. Initialize in application object by extending a custom Application class:

   public class MyApplication extends extends com.activeandroid.app.Application  {
          …
   }

b. Create POJO, derived for a model class, with classes for each of the records you plan to store in the database. Each such POJO can reside in its own table. Annotations should be used to specify the DB fields’ name for each stored member:

     @Table(name = "Categories")
     public class UserDetails extends Model { 
          @Column(name = "Name")
          public String name;
          @Column(name = "Address")
          public String address;
          @Column(name = "Age")
          public int age;
     }

If you wish to set an index for a member, use the following annotation:

          @Column(name = "ID", index = true)
           public String userID;

c. To prevent the library from iterating over all of your classiest startup time, which is the default behaviour, it is highly recommended you specify all of your model classes in the following manifest section:

     <meta-data
        android:name="AA_MODELS"
        android:value=“com.myapp.MyModelA, com.myapp.MyModelB" />

Note: Model classes not appearing in this list will not be recognised by ActiveAndroid.

d. Write to database:

      UserDetails usr = new UserDetails();
      usr.save();  // RUNS ON A BACKGROUND THREAD

If multiple writes are needed, a more efficient way would be to batch them in a single transaction:

    ActiveAndroid.beginTransaction();
    try {
        for (UserDetails u: userList) 
             item.save();
        ActiveAndroid.setTransactionSuccessful();
   }
   finally {
        ActiveAndroid.endTransaction();
   }

e. Read POJOs from database:

   new Select()
         .from(UserDetails.class)
         .where("name = ?", usr.getName())
         .orderBy("Age")
         .executeSingle();

ORM was a must-have tool during my days as a server-side developer. It had a somewhat late entry into the Android domain. But, at last, here it is: database programming as simple as it gets. Enjoy it.

LibStreaming: Painless Video Streaming

Real-time video streaming used to be a major pain because of non-documented APIs, cross-SDK version differences, reflection usage, and more.

libStreaming library animation

Luckily, libStreaming changed all this by encapsulating most of the streaming complexities and exposing a simple and friendly API that allows you to write a basic streaming app in a matter of hours.

In a nutshell, it streamlines video streaming.

To use it for H.264 and AAC, you need to do the following:

a. Initialize a session object at your main activity’s onCreate method. Session objects represent media streaming to a peer:

 protected void onCreate(Bundle savedInstanceState) {
        mSession = SessionBuilder.getInstance()
           .setCallback(this)
           .setSurfaceView(mSurfaceView)
           .setPreviewOrientation(90)
           .setContext(getApplicationContext())
           .setAudioEncoder(SessionBuilder.AUDIO_NONE)
           .setAudioQuality(new AudioQuality(16000, 32000))
           .setVideoEncoder(SessionBuilder.VIDEO_H264)
           .setVideoQuality(new VideoQuality(320,240,20,500000))
          .build();
        mSurfaceView.getHolder().addCallback(this);
    }

b. Actually start the session:

               mSession.setDestination(destination_server_url);
               mSession.start();

c. Halt the session when done:

             mSession.stop();

Now, please do not misunderstand. Real-time streaming is messy by nature and libStreaming does not take away this complexity. However, it does a really good job hiding it from you most of the time. In some cases, you will need to deal with the complexity, such as when selecting peer signalling policy, choosing camera encoding (you’d typically want to use MediaCodec/surface-to-buffer), or dealing with packetization.

Still, you will find that the good guys behind libStreaming went the extra mile in merging these complexities smoothly into a simple-to-use API.

LibStreaming supports most encoders used by Android apps, including H.264, H.263, AAC, and AMR.

I’ve reaped great results with this library. Several of the most popular streaming apps use it as a part of its infrastructure. If you ever encounter the need, I’m certain it’ll make your media streaming experience far smoother.

LeakCanary: Detect Memory Leaks in a Line of Code

Let’s start with the motivation behind this library: memory leaks. Android apps are prone to them, especially if you’re not careful with your coding. In fact, creating memory leaks is very simple. All you need to do is to store an activity reference outside of its context. In fact, even storing a reference to a single view object outside of its activity’s context will create a leak.

Why? Because a view—all views, in fact—internally store a context reference to its containing activity. As long as a reference to the view is kept, its containing activity—along with what’s inside it, including drawables, view hierarchy, and resources—cannot be reclaimed by the garbage collector.

Keeping a reference to a leaking activity is not always obvious as a static parameter. Whenever you create an inner class or spawn a thread inside an activity, a reference to that activity will be created and the activity may not be reclaimed until that inner class or thread are completed.

Leaks are of course not unique to Android, but being a mobile system with limited memory resources, the impact is more immediate.

Leaking a reference to a single resource-intensive activity is sometimes enough to crash your app with an “Out of memory” exception.

LeakCanary library

How can you protect against them? Start with rigorous coding practices, of course. But not all of us are experienced Android developers, and even the experienced devs sometimes forget the rules.

Periodical code reviews with an emphasis on memory leaks may be helpful, but they take time. Also, some leaks are real sneaky and hard to detect by mere code review.

Using the DDMS’ memory tool is a great way of knowing, over time, if your app is leaking. You should definitely use it. However, it will not tell you what’s causing the leak.

Here comes leakCanary to the rescue. It’s the best memory leak detector out there, and it provides automatic — as in one or two lines of code — leak detection for all your activities.

To use it simply initialize leakCanary with your app’s object onCreate():

     public class MyApp extends Application {


          @Override public void onCreate() {
                 super.onCreate();
                 LeakCanary.install(this);
                 // more initialisations
         }
   }

And you’re done. LeakCanary will monitor for memory leaks, and send a notification if it detects one.

LeakCanary achieves this magic by auto-injecting an object called ActivityRefWatcher into all of your activities and monitoring their ref count after onDestroy() has been called. A > 0 ref count on a destroyed activity can only mean a leak.

Important: Leak detection only works for debug mode applications. Never test for leaks (well, not with LeakCanary) in a release mode APK.

But what if I want to test other parts of my system for leaks? Here, LeakCanary offers an object called refWatcher, which is in fact the return value of the initialization call:

            refWatcher  = LeakCanary.install(this);

It can be used to watch values that are soon to be reclaimed. More precisely, values that I think are soon to be reclaimed. To do that, call:

         refWatcher.watch(my_soon_to_be_reclaimed_obj);

The library will let you know if this object has not been released a short time after the watch call.

I could not find the value of this “short time” anywhere, but it’s probably not that important. With leakCanary, things just work. Priceless.

Summary

Experienced developers cut days and weeks off their coding and debugging phases using these libraries, so there is no reason you can’t do the same.

To sum up, here’s what my selection of Android libraries can do for you:

  • ButterKnife – Auto-injected code will help you do away with much of your app’s boilerplate code. It’s the ultimate code injection for Android. Need I say more?

  • AndroidAnnotations – Use blazing fast auto-generated classes and name-based code injection to save time with no performance penalty over hand-coded logic.

  • EventBus – Decouple components for more robust code, cross-component communication has never been simpler.

  • OkHttp – A clever replacement for HttpURLConnection, with support for asynchronous networking, request redirect route query, local cache query, and more.

  • Picasso – Streamlined image manipulation that’s so good it’s now used by Google. It’ a major time-saver in media heavy projects and certain legacy projects.

  • ActiveAndroid – ORM made easy with no performance overhead.

  • LibStreaming – Real-time video streaming, used by major streaming apps.

Are these the only Android libraries worth your time? Certainly not. But I promise you this: Using any of them on your next project will make you a much better developer. If you want to see them in action, take a look at my GitHub.

If you are already using some or all of them, or if you are using alternative libraries, I urge you to share your experiences in the comments below.

Hire a Toptal expert on this topic.
Hire Now
Gilad Haimov

Gilad Haimov

Verified Expert in Engineering

Tel Aviv-Yafo, Israel

Member since July 27, 2015

About the author

Gilad has years of experience in developing Android applications, server-side programs, and communication systems.

authors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.

PREVIOUSLY AT

bmc Software

World-class articles, delivered weekly.

Subscription implies consent to our privacy policy

World-class articles, delivered weekly.

Subscription implies consent to our privacy policy

Join the Toptal® community.