Threading refers to the ability of an application to perform multiple tasks concurrently. This is essential for creating smooth and responsive applications, as it allows for multitasking without freezing or blocking the main user interface (UI). In mobile application development, handling threading properly ensures that tasks like network requests, database operations, or background computations don't interfere with the user experience.
In this guide, we’ll discuss what threading is, how it works, and how to implement threading in Android development.
In programming, a thread is a sequence of instructions that can be executed independently of other threads. Modern operating systems and mobile platforms like Android support multithreading, which allows applications to perform several tasks simultaneously.
Main Thread (UI Thread): This is the thread that controls the user interface. All UI updates must happen on this thread to avoid exceptions. If you perform long-running tasks on this thread, the UI can freeze and become unresponsive.
Worker Threads: These are background threads used to handle long-running tasks such as network calls, file I/O, or intensive calculations. These threads run independently of the UI thread, so they don’t block the user interface.
The main thread, also known as the UI thread, is responsible for interacting with the user interface. In Android, all UI updates (such as displaying a button click or showing a progress bar) must be done on the main thread.
Key points:
To prevent the UI from freezing, you can offload long-running operations to worker threads. Worker threads are used for tasks that take time and should not block the UI, such as:
In Android, you can create a worker thread using the Thread class or AsyncTask (deprecated in API level 30) for simpler tasks. More advanced tasks should use ExecutorService or HandlerThread.
Thread ClassYou can create a new thread in Android by extending the Thread class or implementing the Runnable interface. Here’s a basic example of how to use the Thread class:
public class MyActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create a new thread
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// Background task (e.g., network operation)
performBackgroundTask();
}
});
thread.start(); // Start the thread
}
private void performBackgroundTask() {
// Simulate a long-running task
try {
Thread.sleep(5000); // Simulating a task that takes time
// Update UI after task completion (must run on UI thread)
runOnUiThread(new Runnable() {
@Override
public void run() {
// UI update code (e.g., change text, hide progress bar)
Toast.makeText(MyActivity.this, "Task Completed", Toast.LENGTH_SHORT).show();
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Explanation:
new Thread(new Runnable()) creates a new thread that runs a background task.runOnUiThread() is used to update the UI from the background thread.AsyncTask (Deprecated)The AsyncTask class was designed for performing background operations and updating the UI thread, but it has been deprecated in Android API level 30. For smaller tasks, consider using ExecutorService or Kotlin coroutines (recommended).
Here’s how AsyncTask was used:
private class MyAsyncTask extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground(Void... params) {
// Perform long-running task in background (e.g., network call)
try {
Thread.sleep(5000); // Simulating background task
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Task Completed";
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// Update UI with the result
Toast.makeText(MyActivity.this, result, Toast.LENGTH_SHORT).show();
}
}
// Call the AsyncTask in your activity
new MyAsyncTask().execute();
Explanation:
doInBackground() runs in the background thread and performs the heavy task.onPostExecute() runs on the UI thread after the task is complete, allowing UI updates.Note: AsyncTask is now deprecated in Android, and you are encouraged to use alternatives like Kotlin coroutines, ExecutorService, or Handler.
ExecutorServiceExecutorService is a more flexible and modern way to handle background tasks in Android. It provides a pool of worker threads to execute tasks concurrently.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyActivity extends AppCompatActivity {
private ExecutorService executorService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
executorService = Executors.newFixedThreadPool(2); // Creates a pool with 2 threads
// Submit task to execute in the background
executorService.submit(new Runnable() {
@Override
public void run() {
performBackgroundTask();
}
});
}
private void performBackgroundTask() {
// Simulating a long-running task
try {
Thread.sleep(5000);
// Update UI after task completion (must run on UI thread)
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MyActivity.this, "Task Completed", Toast.LENGTH_SHORT).show();
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Explanation:
ExecutorService manages a pool of threads, allowing you to submit multiple tasks efficiently.submit() method adds tasks to the thread pool for execution.HandlerThreadA HandlerThread is useful for background tasks that require message handling between threads. It’s an easier approach for tasks that require interaction with the Handler (a utility that allows communication between threads).
import android.os.Handler;
import android.os.HandlerThread;
public class MyActivity extends AppCompatActivity {
private HandlerThread handlerThread;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handlerThread = new HandlerThread("BackgroundThread");
handlerThread.start(); // Start the background thread
handler = new Handler(handlerThread.getLooper());
// Post a task to run on the background thread
handler.post(new Runnable() {
@Override
public void run() {
performBackgroundTask();
}
});
}
private void performBackgroundTask() {
// Simulate background work
try {
Thread.sleep(5000);
// Update UI after task completion (must run on UI thread)
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MyActivity.this, "Task Completed", Toast.LENGTH_SHORT).show();
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
handlerThread.quit(); // Clean up when activity is destroyed
}
}
Explanation:
HandlerThread allows you to manage background tasks and ensures you can communicate with the thread’s Handler using its Looper.runOnUiThread() or Handler to update the UI from a background thread.ExecutorService for more complex background tasks, as it can manage multiple threads efficiently.handlerThread.quit()).Threading is a crucial concept in Android development to ensure that long-running tasks (like network calls or database operations) do not block the main UI thread and make the application unresponsive. By using tools like Thread, ExecutorService, or HandlerThread, you can efficiently handle background operations in your Android apps. Just remember that UI updates should always happen on the main thread, and background tasks should run in separate threads to keep the app smooth and responsive.
Open this section to load past papers