Uncategorized

Android Performance: Optimizing Background Tasks with Thread Pooling

silicon-valley-signaling-risk-1Think about the last time you couldn’t stream Game of Thrones on your phone or when you couldn’t load that meme your aunt sent you. Dark and scary times right? But while we take data for granted in the US for people in developing countries, staying connected is expensive. At Jana, we strive create new and innovate ways of delivering free internet to the next billion. mCent, our mobile app, allows our members to earn data by simply trying new apps.

One of the interesting challenges in creating an app for people in developing countries is the fact that we deal with a wide range of devices. Many of our users work with devices that we’ve never even heard of – not just your typical Samsung or Nexus phones. While we might swap our phones ever few years for the latest and greatest, a majority of our users have hardware that we’d consider vastly outdated. We could restrict phones that our app will run on or even have a minimum Android version but that goes against our mission. We need our app to be accessible to those that need it the most.


Over the past few months, we’ve been focused on performance in order to make our app faster and more responsive, regardless of what device our users are on. If you’re an avid fan of Silicon Valley, remember the parts where Gilfoyle would complain about Dinesh‘s crappy code slowing down their compression algorithm? They’d go back and forth about the server setup that Gilfoyle created and Dinesh’s software. In thinking about app development for our users, we should side with Gilfoyle because we can’t rely on hardware to make up for poor performing code. (unless we suddenly decide to go into the business of creating Android devices 🙂 ) Instead we should focus on optimizing our app with the device’s hardware as much as possible.

Ok, enough rambling. Onto the fun stuff!

_62034359_gbdenrowingclosefinish

In this post, I’m going to focus on improving the performance of our background tasks based on the devices resources. Initially, whenever we wanted to run a background task, we’d spin up a new thread, create a runnable, and then execute it. This happened multiple times during app initialization or when a page was rendered.

Let’s consider this on an older phone with less processing power. Take a single core phone for example. There’s a case where we can have several threads running concurrently, each taking longer to complete than if it was the only background task running. All of the threads end up dragging along and everything takes longer to complete because we have 4 threads running on a single core phone 😦

Now let’s think about this from the user’s perspective:

For the purposes of this example, let’s say we have 4 long running tasks:Screen Shot 2015-11-20 at 12.58.03 AM

  • Load an activity feed of what the user’s friends have done ( this is a task that creates a view that the user will see first)
  • Do a complex calculation to create a leaderboard of top users (this is a task that creates a view that is secondary to the activity feed)
  • Store a user’s newly added friends on the app
  • Initialize a 3rd party client

When the user opens up the app, they want to see the activity feed first. We’ll want to make sure that this action takes precedence. Let’s create a work queue to solve this. If we spin up a thread for each task above, all 4 tasks will be running nearly at the same time and that will make loading the activity feed longer to finish processing. 

The fix:

As a fix, we’ll create a thread pool executor that pulls off a work queue. The number of threads available to process tasks depend on the number of cores available so that each thread has a dedicated core for processing the task.

In order to add a task to the queue for processing, we can do something like this:

Now consider the example that we went through above. Let’s say a member’s device has 2 processing cores (2 threads available in the pool) We can add tasks to the queue in the following order:

  1. Load an activity feed of what the user’s friends have done
  2. Do a complex calculation to create a leaderboard of top users
  3. Store a user’s newly added friends on the app
  4. Initialize a 3rd party client

By using a thread pool executor, we will execute tasks 1 & 2 concurrently. Once one of them finishes, that thread will get recycled and then pick up the next task in the queue (task #3). This way, we ensure that the most important UI task gets the attention it deserves first.

Example execution:

  • Load an activity feed of what the user’s friends have done (Thread 1 executing)
  • Do a complex calculation to create a leaderboard of top users (Thread 2 executing)
  • Store a user’s newly added friends on the app
  • Initialize a 3rd party client

      Thread 1 finishes executing …

  • Load an activity feed of what the user’s friends have done (Finished)
  • Do a complex calculation to create a leaderboard of top users (Thread 2 executing)
  • Store a user’s newly added friends on the app (Thread 1 executing)
  • Initialize a 3rd party client

     Thread 2 finishes executing …

  • Load an activity feed of what the user’s friends have done (Finished)
  • Do a complex calculation to create a leaderboard of top users  (Finished)
  • Store a user’s newly added friends on the app (Thread 1 executing)
  • Initialize a 3rd party client (Thread 2 executing)

Couple common errors with background tasks:

  • Anytime you modify a UI element (like a view), you need to run it on the main thread. You can handle this with:

  • ConcurrentModificationException: You’re modifying a shared resource from 2 different threads simultaneously. You’ll want to put a lock on that resource whenever a thread is modifying it.

As with everything we do at Jana, we’ll continue to measure and fine tuning our app so that we can better deliver free internet. Lookout for future posts where we’ll discuss more patterns that we use in order to improve mCent’s experience. Oh, by the way, want to make mCent fly with us? We’re hiring!

Discussion

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s