Archive for June, 2011

Threads in Android Part 2 (updating the UI)

Do we need threads in android? Yes. Especially when you have long running operations like network access. These operations will block the main thread, which runs the user interface (UI), and have the effect that the UI is not able to receive user input. The following example simulates the problem:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    textView = (TextView) findViewById(R.id.textView);
    textView.setText("hello World");

    // simulate long running operation
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        Log.e(TAG, "Thread.sleep", e);
    }
}

Encapsulate processes which might take longer in threads. Particularly when the process is started in the lifecycle of the activity (onCreate, onResume, onPause).
Besides that you may receive an “Application Not Responding (ANR) dialog” from android if the activity is not responding.

So we create a thread which prints a message after finishing it’s work:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    textView = (TextView) findViewById(R.id.textView);
    textView.setText("hello World");

    thread = new Thread() {
        public void run() {
            try {
                // simulate long running operation
                Thread.sleep(5000);
                textView.setText("new value...");
            } catch (InterruptedException e) {
                Log.e(TAG, "run in thread", e);
            }
        }
    };
    thread.start();
}

All set? Not yet. See how you app beautifully dies with a CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. CalledFromWrongThreadException

Just like in Java or C# an UI object (textView in our case) can only be modified by the thread which created it. Which is in our case the main UI thread (not the new thread).

See also the articel Painless Threading on the android developers page. This tutorial here shows how to update the UI from a thread using a Handler.

A handler instance in an activity is bound to the main UI thread. And is able to update UI objects when receiving notifications from other threads.

Next we subclass the Handler class and override the handleMessage method. msg.obj contains the message from the other thread.

private Handler uiHandler = new UIHandler();

class UIHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        // a message is received; update UI text view
        textView.setText(msg.obj.toString());
        super.handleMessage(msg);
    }
}

Create the message object in the long running thread and pass it to the handler. Use Message.obtain() to take a message from a pool of recycled objects:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    textView = (TextView) findViewById(R.id.textView);
    textView.setText("hello World");

    thread = new Thread() {
        public void run() {
            try {
                // simulate long running operation
                Thread.sleep(5000);

                // create message which will be send to handler
                Message msg = Message.obtain(uiHandler);
                msg.obj = "new value...";
                uiHandler.sendMessage(msg);

            } catch (InterruptedException e) {
                Log.e(TAG, "run in thread", e);
            }
        }
    };
    thread.start();
}

The uiHandler object receives the message and prints the content in the UI object.

You have different threads and want to control where the message comes from? Use the msg.what to identify the message:

class UIHandler extends Handler {
    private static final int ID_0 = 0;
    private static final int ID_1 = 1;

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case ID_0:
            // a message is received; update UI text view
            if (msg.obj != null)
                textView.setText(msg.obj.toString());
            break;

        default:
            break;
        }
        super.handleMessage(msg);
    }
}

Change the thread to send a message with the user defined code:

// create message which will be send to handler
Message msg = Message.obtain(uiHandler, UIHandler.ID_0);
msg.obj = "new value...";
uiHandler.sendMessage(msg);

Subversion in Android Projects (using Eclipse)

There is no need to have then bin and gen folder of your android project in the subversion repository. You might as well add then to the ignore list since the content is generated:
bin and gen folder

But what happens if we compile and build the project using eclipse:

.svn folders in bin folder

Eclipse copies the hidden .svn folders from the source directory to the bin folder.

Here is the solution to the problem. Go to the project properties and select Java Build Path. Now add the exclusion pattern **/.svn/ to the source directory:

Java Build Path: exclusion **/.svn/

Cleaning and building the project removes the .svn folders. Notice that the file .classpath has the following new entry: <classpathentry excluding=”**/.svn/” kind=”src” path=”src”/>

Threads in Android Part 1 (infinite loop)

This series shows tips and tricks about using threads in android development. Part 1 describes how to create a thread with an infinite loop. Since we only need the thread while the app is running we must assure that the thread stops when the app is not active.

In this example we create a thread which will execute every n seconds. Look a the following code. We override the onCreate method of the activity and create a thread which will do it’s work and sleep afterward.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    thread = new Thread() {
        public void run() {
            while (true) {
                try {
                    // do something here
                    Log.d(TAG, "local Thread sleeping");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Log.e(TAG, "local Thread error", e);
                }
            }
        }
    };
    thread.start();
}

What happens if the app is pausing? For instance another app comes to the foreground. The following screen shot from the debugger shows that the thread is still running while the app is not active: Debugger: thread is still running

So we need to control the thread and stop it in the onPause method.

The solution is taken from the google article Updating the UI from a Timer (http://developer.android.com/resources/articles/timed-ui-updates.html). We instantiate a Handler which allows us to process Runnable objects.

The Handler it is bound to the main UI thread of the activity. By calling handler.postDelayed(this, 1000); the new thread is added to message queue (of the main UI thread) and will be run after 1 second.

private Thread thread;
private Handler handler = new Handler();

@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);
	
	thread = new Thread() {
		public void run() {
			// do something here
			Log.d(TAG, "local Thread sleeping");
			handler.postDelayed(this, 1000);
		}
	};
}

The rest is easy. We start the thread in the onResume, which is called after onCreate and when the activity comes to the foreground, by calling handler.postDelayed(thread, 0); (parameter 0 shows that there is no delay).

Before adding the thread to the handler we may remove it, to make sure it is not already bound to the handler. onPause does the same:

@Override
protected void onResume() {
	super.onResume();
	
	handler.removeCallbacks(thread);
	handler.postDelayed(thread, 0);
	Log.d(TAG, "onResume");
}

@Override
protected void onPause() {
	super.onPause();

	handler.removeCallbacks(thread);
	Log.d(TAG, "onPause");
}

Looking at the debugger we notice that the thread stopped after pausing the activity: Threads in Android - onResume / onPause