How to Run Code on a Background Thread on Android

Correct way to communicate the result of a background thread to the Ui Thread in Android

Background

In Android, when an application is launched, the system creates a thread of execution for the application, called main thread (also known as the UI thread). Google introduces the main thread and its responsible as below.

The main thread has a very simple design: Its only job is to take and
execute blocks of work from a thread-safe work queue until its app is
terminated. The framework generates some of these blocks of work from
a variety of places. These places include callbacks associated with
lifecycle information, user events such as input, or events coming
from other apps and processes. In addition, app can explicitly enqueue
blocks on their own, without using the framework.

Nearly any block of code your app executes is tied to an event
callback, such as input, layout inflation, or draw. When something
triggers an event, the thread where the event happened pushes the
event out of itself, and into the main thread’s message queue. The
main thread can then service the event.

While an animation or screen update is occurring, the system tries to
execute a block of work (which is responsible for drawing the screen)
every 16ms or so, in order to render smoothly at 60 frames per second.
For the system to reach this goal, the UI/View hierarchy must update
on the main thread. However, when the main thread’s messaging queue
contains tasks that are either too numerous or too long for the main
thread to complete the update fast enough, the app should move this
work to a worker thread. If the main thread cannot finish executing
blocks of work within 16ms, the user may observe hitching, lagging, or
a lack of UI responsiveness to input. If the main thread blocks for
approximately five seconds, the system displays the Application Not
Responding (ANR) dialog, allowing the user to close the app directly.

To update a View, you must do it on the main thread, if you try to update in a background thread, the system will throw CalledFromWrongThreadException.

How to update a View on the main thread from a background thread?

The main thread has a Looper and a MessageQueue assigned with it. To update a View, we need to create a task then put it to the MessageQueue. To do that Android provides
Handler API which allows us to send a task to the main thread's MessageQueue for executing later.

// Create a handler that associated with Looper of the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());

// Send a task to the MessageQueue of the main thread
mainHandler.post(new Runnable() {
@Override
public void run() {
// Code will be executed on the main thread
}
});

To help developers easy to communicate with the main thread from a background thread, Android offers several methods:

  • Activity.runOnUiThread(Runnable)

  • View.post(Runnable)

  • View.postDelayed(Runnable, long)

Under the hood, they use Handler API to do their jobs.

Back to your question

AsyncTask

This is a class that is designed to be a helper class around Thread and Handler. It's responsible for:

  • Create a thread or pool of thread to do a task in the background

  • Create a Handler that associated with the main thread to send a task to the main thread's MessageQueue.

  • It is deprecated from API level 30

ThreadPoolExecutor

Create and handle a thread in Java is sometimes hard and might lead to a lot of bugs if developers do not handle it correctly. Java offers the ThreadPoolExecutor to create and manage threads more efficiently.

This API does not provide any method to update the UI.

Kotlin Coroutines

Coroutines is a solution for asynchronous programming on Android to simplify code that executes asynchronously. But it only available for Kotlin.

So my question is, what is the correct way of communicate the result
of background thread when this finish?.

1. Using Handler or mechanism built on Handler

1.1. If a thread is bounded with Activity/Fragment:

  • Activity.runOnUiThread(Runnable)

1.2. If a thread has a reference to a view, such as Adapter class.

  • View.post(Runnable)

  • View.postDelayed(Runnable, long)

1.3. If a thread does not bound to any UI element, then create a Handler on your own.

Handler mainHandler = new Handler(Looper.getMainLooper);

Note: A benefit of using Handler is you can use it to do 2 ways communication between threads. It means from a background thread you can send a task to the main thread's MessageQueue and from the main thread, you can send a task to the background's MessageQueue.

2. Using BroadcastReceiver

This API is designed to allow Android apps can send and receive broadcast messages from the Android system, other apps or components (Activity, Service, etc) inside the app, similar to publish-subscribe design partern.

Because of the BroadcastReceiver.onReceive(Context, Intent) method is called within the main thread by default. So you can use it to update the UI on the main thread. For example.

Send data from a background thread.

// Send result from a background thread to the main thread
Intent intent = new Intent("ACTION_UPDATE_TEXT_VIEW");
intent.putExtra("text", "This is a test from a background thread");
getApplicationContext().sendBroadcast(intent);

Receive data from activity/fragment

// Create a broadcast to receive message from the background thread
private BroadcastReceiver updateTextViewReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String text = intent.getStringExtra("text");
myTextView.setText(text);
}
};

@Override
protected void onStart() {
super.onStart();
// Start receiving the message
registerReceiver(updateTextViewReceiver, new IntentFilter("ACTION_UPDATE_TEXT_VIEW"));
}

@Override
protected void onStop() {
// Stop receving the message
unregisterReceiver(updateTextViewReceiver);
super.onStop();
}

This method is usually used to communicate between Android apps or Android apps with the system. Actually, you can use it to communicate between components in Android app, such as (Activity, Fragment, Service, Thread, etc.), but it requires a lot of code.

If you want a similar solution but less code, easy to use, then you can use the following method.

3. Using EventBus

EventBus is a publish/subscribe event bus for Android and Java. If you want to execute a method that runs on the main thread, just mark it with @Subscribe(threadMode = ThreadMode.MAIN) annotation.

// Step 1. Define events
public class UpdateViewEvent {
private String text;

public UpdateViewEvent(String text) {
this.text = text;
}

public String getText() {
return text;
}
}

// Step 2. Prepare subscriber, usually inside activity/fragment
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
myTextView.setText = event.getText();
};

// Step 3. Register subscriber
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}

// Step 4. Unregister subscriber
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}

// Step 5. Post events from a background thread
UpdateViewEvent event = new UpdateViewEvent("new name");
EventBus.getDefault().post(event);

This is useful when you want to update a View when the activity/fragment is visible to users (they are interacting with your app).

How to run task using Thread in Background

please check the sample -

 public class EventHandlerImplementation extends EventHandler {
private EventHandlerImplementation(EventRunner runner) {
super(runner);
}

@Override
public void processEvent(InnerEvent event) {
getUITaskDispatcher().asyncDispatch(() -> {
// do your stuff here
});
}
}

Starting a runnable in background thread

custListLoadThread = new Thread(loadRunnable);
custListLoadThread.start();

You need to start the thread, not call the run() method in the current thread.

How should I put code in Background Thread in Java?

You can call enqueue method instead of execute and it will work on the background thread:

client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
// handle your response
}

@Override
public void onFailure(Call call, IOException e) {
// handle the failure
}
});

Running code in the background and validating the thread

My guess is you have to specify the type of thread priority with setThreadPriority. Try as follows:

new Thread(new Runnable() {
public void run() {
// moves the current Thread into the background
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_BACKGROUND);

// doing some work in the background here
Log.d(tag, "Thread: " + checkThread());
}
}).start();

This should be return background.

Android: Create a background thread that runs periodically and does UI tasks?

Maybe you are better of, creating a seperate (Intent)Service and calling it periodically with postDelayed. Create a BroadcastReceiver in your Activity and handle UI changes there.

Another hint for handling UI changes from other threads: It is not possible. Therefore you need to call runOnUiThread. Here is how to use it



Related Topics



Leave a reply



Submit