Monday, April 29, 2013

Handling Configuration Changes with Fragments

This post addresses a common question: what is the best way to retain active objects—such as running Threads, Sockets, and AsyncTasks—across device configuration changes?

To answer this question, we will first discuss some of the common difficulties developers face when using long-running background tasks in conjunction with the Activity lifecycle. Then, we will describe the flaws of two common approaches to solving the problem. Finally, we will conclude with sample code illustrating the recommended solution, which uses retained Fragments to achieve our goal.

Configuration Changes & Background Tasks

One problem with configuration changes and the destroy-and-create cycle that Activitys go through as a result stems from the fact that these events are unpredictable and may occur at any time. Concurrent background tasks only add to this problem. Assume, for example, that an Activity starts an AsyncTask and soon after the user rotates the screen, causing the Activity to be destroyed and recreated. When the AsyncTask eventually finishes its work, it will incorrectly report its results back to the old Activity instance, completely unaware that a new Activity has been created. As if this wasn't already an issue, the new Activity instance might waste valuable resources by firing up the background work again, unaware that the old AsyncTask is still running. For these reasons, it is vital that we correctly and efficiently retain active objects across Activity instances when configuration changes occur.

Monday, April 15, 2013

Activitys, Threads, & Memory Leaks

A common difficulty in Android programming is coordinating long-running tasks over the Activity lifecycle and avoiding the subtle memory leaks which might result. Consider the Activity code below, which starts and loops a new thread upon its creation:

/**
 * Example illustrating how threads persist across configuration
 * changes that destroy the underlying Activity instance. The 
 * Activity context also leaks because the thread is instantiated
 * as an anonymous class, which holds an implicit reference to the
 * outer Activity instance, therefore preventing it from being
 * garbage collected.
 */
public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    exampleOne();
  }

  private void exampleOne() {
    new Thread() {
      @Override
      public void run() {
        while (true) {
          SystemClock.sleep(1000);
        }
      }
    }.start();
  }
}

Note: the source code in this blog post is available on GitHub.

When a configuration change occurs, causing the entire Activity to be destroyed and re-created, it is easy to assume that Android will clean up after us and reclaim the memory associated with the Activity and its running thread. However, this is not the case. Both will leak never to be reclaimed, and the result will likely be a significant reduction performance.

Monday, January 14, 2013

How to Leak a Context: Handlers & Inner Classes

Consider the following code:

public class SampleActivity extends Activity {

  private final Handler mLeakyHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      // ... 
    }
  }
}

While not readily obvious, this code can cause cause a massive memory leak. Android Lint will give the following warning: "In Android, Handler classes should be static or leaks might occur." But where exactly is the leak and how might it happen? Let's determine the source of the problem by first documenting what we know:

  1. When an Android application first starts, the framework creates a Looper object for the application's main thread. A Looper implements a simple message queue, processing Message objects in a loop one after another. All major application framework events (such as Activity lifecycle method calls, button clicks, etc.) are contained inside Message objects, which are added to the Looper's message queue and are processed one-by-one. The main thread's Looper exists throughout the application's lifecycle.

  2. When a Handler is instantiated on the main thread, it is associated with the Looper's message queue. Messages posted to the message queue will hold a reference to the Handler so that the framework can call Handler#handleMessage(Message) when the Looper eventually processes the message.

  3. In Java, non-static inner and anonymous classes hold an implicit reference to their outer class. Static inner classes, on the other hand, do not.

Saturday, January 12, 2013

Use Go to Implement your Android Backends!

A couple weeks ago I wrote a library that simplifies the interaction between Go-based application servers and Google Cloud Messaging servers. I plan on covering GCM (both the application-side and server-side aspects) in more detail in a future blog post, but for now I will just leave a link to the library to encourage more people to write their GCM application servers using the Go Programming Language (Google App Engine, hint hint).

...but why Go?

I'm glad you asked. There are several reasons:

  • Go is modern. Programming languages like C, C++, and Java are old, designed before the advent of multicore machines, networking, and web application development. Go was designed to be suitable for writing large Google programs such as web servers.

  • Go is concise, yet familiar. Tasks that require 40+ lines of code in Java (i.e. setting up HTTP servers and parsing JSON responses) can be done in 1 or 2 lines. Go significantly reduces the amount of work required to write simple programs, and yet the language's syntax is not too radical, still resembling the most common procedural languages.

  • Go is easy to learn. Learn the language in a day: A Tour of Go and Effective Go.

  • Go was invented at Google. Enough said.

That's all for now... but expect a lot more on GCM, Google App Engine, and Golang later! The comments are open as always, and don't forget to +1 this post!

Links