Threading in Android

Table of Contents
What is Threading in Android
When we write functions methods or any code and want to execute some piece of code it goes to some kind of queue so it is waiting for its turn to execute and that queue is pretty much a thread.
package com.rishiz.app;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this,"MainActivity Toast",Toast.LENGTH_SHORT).show();
for (int i=0;i<20;i++){
Log.d("Output","for loop "+i);
}
int x=10;
while(x<25){
x++;
Log.d("Output","while loop "+x);
}
}
}
So each piece of code goes into the queue or thread and waits until it’s time to execute.
In the above code first, the setContentView is executed it will set our view and layout and when it is finished toast pop-up will show.
for loop start executed when toast pop-up executed, we can’t have it simultaneously.
After the execution of the for loop while loop is executed.
So you can see that everything in for loop is executed and after it is finished while the loop is executed.
There is no chance to execute a while loop before a for loop that is because the for loop and while are on the same thread and if something is in the thread then it must wait until its turn.
Let’s imagine that for loop is some kind of downloading from the internet and while loop is the user trying to open the home page in that case user can’t able to open the home page until the downloading process is completed.
Therefore to deal with this we are using multithread so that the downloading process can be done on different threads and the user can do their task on the app without blocking.
While executing for loop while loop is blocked by default in Android everything is executed on UI or main thread(UI and main thread are the same thing).
While using Firebase by default the operation like downloading or the operations that block others is executed in the background.
Types of thread
- UI Thread (Main Thread):
- The UI thread is the main thread of an Android application responsible for handling user interface interactions and rendering the UI.
- It’s where all UI components are created, updated, and interacted with.
- It should be kept responsive, as any long-running operation on the UI thread can lead to an “Application Not Responding” (ANR) error and a frozen UI.
- Background Threads:
- Background threads are used to perform tasks that are not directly related to the UI, such as network requests, file I/O, database operations, and other time-consuming tasks.
- Executing long-running operations on the UI thread can cause UI freezes and a poor user experience, so such tasks should be offloaded to background threads.
Multithreading in Android
Multithreading in Android refers to the ability of an Android application to execute multiple threads concurrently. A thread is a unit of execution within a process. Multithreading allows an application to perform multiple tasks concurrently, which can lead to improved performance and responsiveness.
Application Not Responding error
Create two buttons and do the following operations.
package com.rishiz.app;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
Button btnClick;
Button btnDownloading;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnClick = findViewById(R.id.button);
btnDownloading = findViewById(R.id.button2);
btnClick.setOnClickListener(v -> {
Toast.makeText(this, "MainActivity Toast", Toast.LENGTH_SHORT).show();
});
btnDownloading.setOnClickListener(v -> {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Log.d("Output", "for loop " + i);
}
});
}
}
On click of the downloading button, we have to simulate the downloading to achieve this we are using Thread.sleep it will pause the execution on a current thread for the given time.
So you see that the log is printed on waiting of 1 second each time.
The simulated downloading process button seems to be pressed and the user is not able to click the UI process button.
So when we click the button for downloading it is in a pressed state until the downloading process is completed(in our case downloading = execution of for loop)
once the downloading is completed users can able to click on another button or other views.
But if the user does anything while the execution of downloading app will crash with the error “Application Not Responding error” thats because ui thread is blocked.
In Android, by default, everything is executed on the UI thread until we explicitly do not execute this on the background thread.
So to fix this create a new thread to execute the downloading process in the background thread.
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<20;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Log.d("Output","for loop "+i);
}
}
}).start();
We are now able to click the UI process button the UI thread is not blocked anymore now because we are simultaneously running two operations, downloading and the clicking button UI process.
Implementation of Threading in Android
- Running Code on the UI Thread
To run code on the UI thread, you can use the runOnUiThread
method from the Activity
class.
runOnUiThread(new Runnable() {
@Override
public void run() {
// code to run on the UI thread
}
});
we’re using the runOnUiThread
method to run some code on the UI thread. This method takes a Runnable
object as its argument, which contains the code to be executed on the UI thread.
2. Creating a Background Thread
To create a new background thread, you can use the Thread
class and pass a Runnable
object to its constructor.
new Thread(new Runnable() {
@Override
public void run() {
// background task
}
}).start();
3. Using Kotlin Coroutines
Kotlin Coroutines is a lightweight framework for performing asynchronous operations in Kotlin. It provides a simple and elegant way to write asynchronous code that is easy to read and maintain.
GlobalScope.launch {
// background task
}
we’re using the launch
function from the GlobalScope
object to start a new coroutine that will perform the background task. The launch
function returns a Job
object, which can be used to cancel the coroutine if needed.
4. Using Handler
The Handler
class is used to send and process messages between threads. It’s commonly used to perform delayed or periodic background tasks
val handler = Handler()
handler.postDelayed({
// background task
}, 1000)
In this example, we’re creating a new Handler
object and using its postDelayed
method to schedule a background task to be executed after a delay of 1000 milliseconds (1 second). The postDelayed
method takes a Runnable
object as its first argument, which contains the background task to be executed.
5. Using ExecutorService
ExecutorService
is a powerful concurrency framework that allows you to manage a pool of threads and execute tasks concurrently
val executorService = Executors.newFixedThreadPool(4)
executorService.submit {
// background task
}
executorService.shutdown()
In this example, we’re creating a new ExecutorService
object with a fixed pool size of 4 threads. We’re using its submit
method to submit a Runnable
object that contains the background task we want to perform. Finally, we’re calling the shutdown
method to stop the ExecutorService
and release its resources.
6. Using IntentService
IntentService
is a class in Android that allows you to perform background tasks in a separate thread. It’s commonly used for tasks that need to be performed in the background, but don’t need to run continuously. Here’s an example of how to use it:
class MyIntentService : IntentService("MyIntentService") {
override fun onHandleIntent(intent: Intent?) {
// background task
}
}
we’re creating a new MyIntentService
class that extends IntentService
. We’re overriding the onHandleIntent
method to perform the background task. The onHandleIntent
method is called on a separate thread, so you don’t need to create a new thread yourself.
7. Using RxJava
RxJava is a popular reactive programming library that allows you to create asynchronous and event-driven programs.
Observable.fromCallable {
// background task
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { result ->
// code to run on the UI thread
}
In this example, we’re using the fromCallable
method to create an Observable
object that contains the background task we want to perform. We’re using the subscribeOn
method to specify that the task should run on the io
scheduler, which is optimized for I/O-bound tasks. We’re using the observeOn
method to specify that the result should be delivered on the main thread. Finally, we’re using the subscribe
method to handle the result.
8. Using HandlerThread
HandlerThread
is a class in Android that allows you to create a thread that has a Looper
associated with it. This makes it easy to perform tasks on a separate thread and communicate back to the main thread. Here’s an example of how to use it:
class MyHandlerThread : HandlerThread("MyHandlerThread") {
private lateinit var handler: Handler
override fun onLooperPrepared() {
handler = Handler(looper)
}
fun postTask(task: Runnable) {
handler.post(task)
}
}
we’re creating a new MyHandlerThread
class that extends HandlerThread
. We’re overriding the onLooperPrepared
method to create a new Handler
object that’s associated with the thread’s Looper
. We’re also defining a postTask
method that allows us to post a Runnable
object to the thread’s Handler
.
To use the MyHandlerThread
class, we can create a new instance of the class and call its start
method to start the thread:
val myHandlerThread = MyHandlerThread()
myHandlerThread.start()
myHandlerThread.postTask {
// background task
}
we’re creating a new MyHandlerThread
object and starting the thread. We’re using the postTask
method to post a Runnable
an object that contains the background task we want to perform.
There are various ways to utilize threads in Android Kotlin, each with its benefits and drawbacks. When selecting a concurrency framework, it’s important to consider factors like performance, complexity, and ease of use.
[…] To gain a better understanding of threading in Android, I recommend reading the article Threading in Android (rishiz.site) […]