Threads and Android

The default is for an application to run in a single thread, known as the “main” or “UI” thread. You can create separate threads to run time-consuming operations. Otherwise, the UI will not be able to respond to users during execution of those operations. Android might decide to shut down a thread if memory is low and other, more immediate, processes are needed. Android will restart any processes that it shuts down when there is work for them to do again. Typically, Android will shut down threads in the following order:

  • a empty process—that is, a process that’s been cached but is no longer active.
  • a background process. Background processes are usually stopped on a last-shown, last-out basis, which is known as a least recently used (LRU) basis.
  • a service that is not visible.
  • a visible process that is not in the foreground, e.g. toasts.
  • a foreground process.

Android Thread Techniques

Technique I

Technique I can be used with very simple threads that do not update the UI. Anything that updates the UI should be done inside the UI thread.

Create an instance of a thread with an instance of runnable and override the run() method to execute the time-consuming task. Start the thread, and the thread will run the task.

public boolean onTouch(final View v, final MotionEvent motionEvent) {
	Thread backgroundThread = new Thread(new Runnable() {
		@Override
		public void run() {
			timeConsumingTask();
		} // end run
	}); // end backgroundThread

	backgroundThread.start();
} // end onTouch
Technique II

This technique is used with more complicated threads that do not update the UI. It consists of creating a subclass of the thread class and overriding the run() method. When the thread is started, its run() method will execute.

class BackgroundThread extends Thread {
	// this method will be called when the thread starts
	@Override
	public void run() {
		timeConsumingTask();
	} // end run
} // end BackgroundThread

Thread backgroundThread = new BackgroundThread();
backgroundThread.start(); 
Technique III

Another technique to use with more complicated threads that do not update the UI is to implement runnable instead of extending thread. The main differences between extending a thread and implementing runnable are:

  • A class must extend a thread, which means that it can not extend another class. Runnable is an interface. A class that implements runnable can still extend another class.
  • A thread creates a unique object every time you use it. Runnable shares the same object with multiple threads.

Create a class that implements runnable and perform the time-consuming tasks in the run() method. When you want to execute the tasks, create a thread with an instance of the runnable subclass and start the thread. When the thread is started, the run() method will execute.

class BackgroundRunnable implements Runnable {
	// this method will be called when the thread starts
	public void run() {
		timeConsumingTask();
	} // end run
} // end BackgroundRunnable

Runnable backgroundThread = new Thread(new BackgroundRunnable(), 
		"backgroundThread");
backgroundThread.start();
Technique IV

This is a simple technique that can be used with threads that update the UI. This technique is typically used in event-driven methods, such as onTouch() and onClick(), to update the view. Since anything that updates the UI should be done from inside the UI thread, a view is used to post the runnable.

Create an instance of a thread with an instance of runnable, and override the run() method so that it performs the time consuming-task and posts the result to a view. Start the thread and the thread will run the task.

public boolean onTouch(final View v, final MotionEvent motionEvent) {
	Thread backgroundThread = new Thread(new Runnable() {
		@Override
		public void run() {
			text = timeConsumingTask();
			label.post(new Runnable() {
				@Override
				public void run() {
					label.setText(text);
				} // end inner run 
			} // end post
		} // end outer run
	}); // end backgroundThread

	backgroundThread.start();
} // end onTouch
Technique V

This is another simple technique that can be used with threads that update the UI. This technique is very similar to the preceding one. It typically is used in event-driven methods, such as onTouch() and onClick(), to update the view. Since anything that updates the UI should be done from inside the UI thread, a view is used to post the runnable. The difference between this technique and the previous one is that this technique provides a delay (in milliseconds).

Create an instance of a thread with an instance of runnable, and override the run() method so that it performs the time consuming-task and posts the result to a view. Start the thread and the thread will run the task.

public boolean onTouch(final View v, final MotionEvent motionEvent) {
	Thread backgroundThread = new Thread(new Runnable() {
		@Override
		public void run() {
			text = timeConsumingTask();
			label.postDelayed(new Runnable() {
				@Override
				public void run() {
					label.setText(text);
				} // end inner run
			}, 3000); // end postDelayed
		} // outer run
	} // end backgroundThread 

	backgroundThread.start();
} // onTouch
Technique VI

Yet another, very similar, technique that can be used with threads that update an activity. The main difference between post() and runOnUiThread() is that runOnUiThread() updates an activity, not a view. The two tend to overlap, but there will be times when you do not have access to a view in an activity, and vica versa. Another difference is that runOnUiThread() checks the current thread and executes runnable immediately if it is in the main thread. Post() always puts the runnable on the queue, no matter what thread it is in.

Create an instance of a thread and override the run() method so that it performs the time consuming-task and runs on the UI to send the result to an activity. Start the thread and the thread will run the task.

Thread backgroundThread = new Thread("thread1") {
	@Override
	public void run() {
		layout = timeConsumingTask();
		anActivity.runOnUiThread(new Runnable() {
			public void run() {
				anActivity.setContentView(layout);
			} // end inner run
		}); // end runOnUiThread
	} // end outer run
}; // end backgroundThread

backgroundThread.start();
Technique VI

This is a simple technique that can be used to update a UI. This technique is for countdown timers that display the time remaining. A label is used to display the text.

Create an instance of a CountDownTimer. Override the onTick() and onDone() methods to update the UI.

CountDownTimer countDownTimer = new CountDownTimer(6000, 1000) {
	@Override
	public void onTick (long millisUntilFinished) {
		countDownLabel.setText("seconds remaining: " +
		milliseconds/1000);
	} // end onTick
	@Override
	public void onDone() {
		countDownLabel.setText("done!")
	} // end onDone
} // end countDownTimer

countDownTimer.start();
Technique VII

Another, old, technique is to use a handler to send messages between threads. The background thread executes and sends the result back to the handler, which updates the main thread.

Create a handler and a background thread. Start the thread and use a handler to obtain a message from the background thread and to update the main thread with the retrieved message.

Handler handler = new Handler() {
	@Override
	public void handleMessage(Message message) { 
		label.setText(message);
	} // end handleMessage 
} // end handler

public boolean onTouch(final View v, final MotionEvent motionEvent) {
	Thread backgroundThread = new Thread() {
		@Override
		public void run() {
			String text = timeConsumingTask();
			Message message = Handler.obtainMessage();
			message = text;
			handler.sendMessage(message);
		} // end run
	}); // end backgroundThread

	backgroundThread.start();
} // end onTouch
Technique VIII

This is another technique that we can use to the perform time-consuming tasks in a background thread and update the UI in the main thread. This technique is typically used for more complex tasks than simply changing the view on a simple onTouch() or onClick() event.

Create a subclass of AsyncTask. AsyncTask creates a background thread and publishes the results to the UI thread. To subclass AsyncTask, you must implement the doInBackground() callback method, which runs as a background thread, and the onPostExecute() method, which gets the result from doInBackground() and updates the UI. Call execute() on an instance of the AsyncTask subclass start execution.

class BackgroundAsyncTask extends AsyncTask<Type1, Type2, Type3> {
	protected Type3 doInBackground(Type1... type1variables) {
		// is returned to onPostExecute method
		return getType3variable(type1variables[0]); 
	} // end doInBackground
	protected Type2 onPostExecute(Type3 result) {
		view.setType2variable(result);
	} // end onPostExecute
} // end BackgroundAsyncTask

The first specified type for AsyncTask is the same as for the argument for doInBackground. The second specified type for AsyncTask, which is typically Void, is the same as the return type for onPostExecute. And the third specified type for AsyncTask is the same as the return type for doInBackground and the argument type for onPostExecute.

It is possible for the background thread to get destroyed due to a runtime configuration change, such as changing screen orientation or opening/hiding the keyboard). When runtime configuration changes occur, Android calls the onDestroy() method followed by onCreate(). You can save the state of the activity in the onPause(), onStop(), or onDestroy() method so that the state can be restored in the onCreate() or onRestoreInstanceState() method. The more complex saving and restoring state, the slower the application will run. If the application slows down substantially, then you do have a couple of other options.

You could retain the state in a state object and carry the state object to the new instance of your activity. To retain an object during a runtime configuration change, override the onRetainNonConfigurationInstance() method so that it returns the state object. When the activity is created again, call getLastNonConfigurationInstance() to recover the state object. This technique is typically used to carry over data. It should not be used to carry over activity-related objects, such as Drawable, Adapter, View, which would cause memory leaks. The garbage collector can not collect any activity-related objects that are carried over.

@Override
public Object onRetainNonConfigurationInstance() {
		final MyDataObject data = getData();
		return data;
} // end onRetainNonConfigurationInstance

You can also prevent the system from restarting the activity and receive a callback when configurations do change and then manually update the activity yourself. Handling configuration change yourself makes it difficult to use alternative resources because the Android system does not automatically apply them for you. Therefore, you should use this technique as a last resort.

Edit the <activity> element in the manifest file to include android:configChanges with the attribute value that corresponds to the configuration you are going to manually handle.

<activity android:name=".MyActivity"
		android:configChanges="orientation|screenSize"
		andriod:label="@string/app_name">

@Override
public void onConfigurationChanged(Configuration configuration) {
	super.onConfigurationChanged(configuration);
	if(configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
		…
	} else if (configuration.orientation == 
			configuration.ORIENTATION_PORTRAIT) {
		…
	}
} // end onConfigurationChanged

When selecting a technique, keep in mind performance and memory issues. It is generally preferable to use AsyncTask than to create your own threads. When you create your own threads, you are in reality creating a new thread every time you execute the thread. AsyncTask, on the other hand, uses a static pool containing a maximum of 128 threads, and it will reuse an old thread whenever it can.

Your application might keep threads alive after they finish executing, resulting in memory leaks that can slow down the application if you don’t get rid of the threads before an activity gets destroyed. So if you create your own threads, then make sure you remove them when they aren’t needed anymore.

Your application might also keep an AsyncTask alive. You can call cancel(true) to make sure the AyncTask instance is canceled when it is not need anymore.

Whatever techniques you use, make sure all your methods are thread safe. This is especially true for methods, such as bound service and content provider methods, that can be called remotely or from a pool of threads.

This entry was posted in Developers. Bookmark the permalink.

One Response to Threads and Android

  1. Pingback: Hermes Outlet

Leave a Reply

Your email address will not be published. Required fields are marked *