I have a code sample that uses this function to run a thread runOnUiThread. why and when may we need to use it?
edit
What about to use AsyncTask class, what's the pros and cons??
You have to use runOnUiThread() when you want to update your UI from a Non-UI Thread. For eg- If you want to update your UI from a background Thread. You can also use Handler for the same thing.
From the Docs -
Runs the specified action on the UI thread. If the current thread is
the UI thread, then the action is executed immediately. If the current
thread is not the UI thread, the action is posted to the event queue
of the UI thread.
Syntax -
Activity_Name.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// your stuff to update the UI
}
});
Update -
AsyncTask -
If you want to do some Network operation or anything that blocks
your UI in that case AsyncTask is best options. There are several
other ways for performing the same Background Operations as you can
use Service, IntentService also for doing Background Operations.
Using AsyncTask will help you doing your UI work and also won't block
your UI until your background Operation is going on.
From the Docs -
AsyncTask enables proper and easy use of the UI thread. This class
allows to perform background operations and publish results on the UI
thread without having to manipulate threads and/or handlers.
To update userinterface from thread you need to use runOnUiThread. But using asynctask is better than using runonuithread. android-runonuithread-vs-asynctask this link can help you
Related
I have a ProgressBar in .xml that I want to show when a long-running operation. I use
ProgressBar progressSpinner = (ProgressBar)findViewById(R.id.progressSpinner);
progressSpinner.setVisibility(View.VISIBLE);
to set its visibility in some onButtonClick method. If the above code is all that is in the method, it works just fine. The problem is when I have a method like this:
public void onButtonClick (android.view.View view){
ProgressBar progressSpinner = (ProgressBar)findViewById(R.id.progressSpinner);
progressSpinner.setVisibility(View.VISIBLE);
longRunningMethod(); // This method takes 5-10 seconds to run
progressSpinner.setVisibility(View.GONE);
}
The UI just locks up until longRunningMethod is done. That method works just fine, but the spinner never shows.
I tried running everything on a different thread with this:
public void onButtonClick (android.view.View view){
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(this::longRunningMethod);
}
And I added the spinner visibility changing stuff to longRunningMethod:
private void longRunningMethod(){
ProgressBar progressSpinner = (ProgressBar)findViewById(R.id.progressSpinner);
progressSpinner.setVisibility(View.VISIBLE);
// Logic that takes 5-10 seconds to run.
progressSpinner.setVisibility(View.GONE);
}
When I do this, the UI doesn't lock up, but nothing in longRunningMethod works. The spinner won't show and the logic also doesn't seem to work, although this may just be a problem with that logic not playing nice on not-the-UI-thread. I am very confused that the spinner visibility won't update from here though.
For running long task operations, you should use Worker Thread.
You must run your task in worker thread and then return task results to UI.
First method is using AsyncTask:
AsyncTask was intended to enable proper and easy use of the UI thread. However, the most common use case was for integrating into UI, and that would cause Context leaks, missed callbacks, or crashes on configuration changes. It also has inconsistent behavior on different versions of the platform, swallows exceptions from doInBackground, and does not provide much utility over using Executors directly.
Second one is using Pure Thread
All Android apps use a main thread to handle UI operations. Calling long-running operations from this main thread can lead to freezes and unresponsiveness. For example, if your app makes a network request from the main thread, your app's UI is frozen until it receives the network response. You can create additional background threads to handle long-running operations while the main thread continues to handle UI updates.
official document
and the last method is using Coroutine (just for kotlin)
if you are using kotlin i suggest this one otherwise use AsyncTask
Just try to run your tasks in other Thread and return results by using a callback like interface
first of all I recommend that get familiar with threads in android :
https://developer.android.com/guide/components/processes-and-threads
then , there is some lib to manage threads
AsyncTask , Couroutin , Rxjava . . .
Taking Sina's suggestion to use a Thread, the class now looks like:
public class MainActivity extends AppCompatActivity{
// Irrelevant code (fields, init, other button handlers, etc...)
private void onButtonClick(android.view.View view){
LongRunningThread longRunningThread = new LongRunningThread();
longRunningThread.start();
}
private class LongRunningThread extends Thread{
public void run(){
runOnUiThread(MainActivity.this::showSpinner);
// Logic that takes 5-10 seconds to run
runOnUiThread(MainActivity.this::hideSpinner);
}
}
private void showSpinner(){
ProgressBar progressSpinner = (ProgressBar)findViewById(R.id.progressSpinner);
progressSpinner.setVisibility(View.VISIBLE);
}
private void hideSpinner(){
ProgressBar progressSpinner = (ProgressBar)findViewById(R.id.progressSpinner);
progressSpinner.setVisibility(View.GONE);
}
}
Doing this shows the progress spinner while the long-running logic is running and then hides the progress spinner after the long-running logic has completed. The UI stays responsive throughout and doesn't lock up.
Compared to the original code, this uses Thread instead of ExecutorService. It also runs UI logic via AppCompatActivity.runOnUiThread().
It would seem the answer to doing any long-running tasks alongside UI updates, without locking up the UI, is to create a Thread and call Thread.start(). The Thread should contain the long-running logic as well as the UI logic. The UI logic within that Thread must be run using runOnUiThread().
I am still confused at threads. Still I could see some answers which points to threads, UI thread, background thread, main thread etc. (mostly on AsyncTasks and updating UI from background threads etc.)
Could anyone give me a complete explanation around these or some links at least?
It would be great if the answer covers the following cases:
Which are all the threads that's involved:
When I am running an activity (setting the content view, attaching some buttons, some dialog messages)
An activity with AsyncTask
A Background Service
A HTTP call
UI thread (main thread) - it is crucial to instantiate (add) all UI elements on this thread, that is why it has a nickname UIThread
AsyncTask - has methods doInBackground, onPostExecute, etc. Sort of its own lifecycle
Background Service (service) A service runs by default in the same process as the application. in its own thread. (as pointed out by #MisterSmith) A service runs by default in the same process as the application. in its own thread. Therefore you need to use asynchronous processing in the service to perform resource intensive tasks in the background. Services which run in the process of the application are sometimes called local services.
Thought you can specify to run a Service in its own process:
Running a service in its own process will not block the application in case the service performs long running operations in its main thread. But as the services runs in its own process you need to use some interprocess communication (IPC) to communicate to your service from other parts.
HTTP call executed using HttpClient (from docs:
Thread safety of HTTP clients depends on the implementation and
configuration of the specific client.
), has to be executed on non-UI thread by using new Thread(new Runnable(...)).start();, otherwise you will get NetworkOnMainThreadException thanks to #vikram. But it seems that HttpClient.execute() method is executed in a thread, that is why it requires a handler as one of the parameters in order to pass the result to the corresponding handler (handler runs on UI thread and can update widgets (UI elements) as it is needed)
Extra:
To force something to be executed on your main thread use yourContextInstance.runOnUiThread(new Runnable(....));
In order to determine if current thread is UI(main) thread:
Looper.getMainLooper().getThread() == Thread.currentThread();
Interesting question about threads in a service:
Does a runnable in a service run on the UI thread
Why UI thread is responsible for all this?
Because UI thread is in charge of dispatching the events to the
appropriate widgets (UI elements), which includes the drawing events
Sources: this that and a little bit of that and some of that
When I am running an activity ( seting a content view , attaching some buttons, some dialog messages )
Usually only one thread (the main one, sometimes incorrectly called UI thread).
Activity - with async task
Again, by default only one (the main one). Menus and button handlers also run in the main thread. AsyncTask is a different story. It creates a worker thread (btw you should be careful not to leak it when exiting the activity).
Background Service
A service runs by default in the main thread. So do broadcast receivers. And this is why the main thread is not (only) the UI thread. Some types of services (like the popular IntentService) spawn a worker thread though.
An http Call
Is a synchronous operation, so it blocks until it completes (and this is why you should never perfom one in the main thread).
Technically speaking an application can have as many threads as it wants, they are arbitrarily created by the programmer.
However, the standard android application by default has one thread. That is the main thread, and is often referred to as the UI thread (as it is the only thread with access to the UI). By default everything happens in the main thread.
If you run an async task, different parts run in different threads, here's a basic breakdown:
onPreExecute() runs in the UI thread and is first called when you execute an async task.
doInBackground() runs in a newly spawned thread separate from the main/UI thread.
onPostExecute() runs in the UI thread after the background task returns.
A background service runs entirely separately from the application, it can run indefinitely even if the original application is destroyed.
An http call happens on whatever thread you call it on, but as a requirement of newer android API's you can no longer do any network activity from the main/UI thread. (This will actually cause an exception and terminate your application) This is to prevent slow network calls from blocking the main thread and therefore creating a choppy user experience.
Which are all the threads that's involved:
When I am running an activity (setting the content view, attaching some buttons, some dialog messages)
UI Thread or Main Thread is involved here.
An activity with AsyncTask
Both UI Thread and WorkerThread is involved.
AsyncTask enables proper and easy use of the UI thread. This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
The 4 steps
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). This method is used to display any form of progress in the user interface while the background computation is still executing.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
A Background Service
The IntentService class provides a straightforward structure for running an operation on a single background thread. This allows it to handle long-running operations without affecting your user interface's responsivenes
A HTTP call
NetwokrkOperation can't be executed from UI Thread ( or MainThread). So use alternatives like AsyncTask or HandlerThread
Related posts:
Handler vs AsyncTask vs Thread
Why use HandlerThread in Android
Asynctask vs Thread vs Services vs Loader
Is there any way on Android to know, if the thread running my code, is the UI Thread or not ? In swing there was SwingUtilities.isEventDispatchThread() to tell me if i am on the UI Thread, or not. Is there any function in the Android SDK that lets me know this ?
Answer borrowed from here: How to check if current thread is not main thread
Looper.myLooper() == Looper.getMainLooper()
Any Android app has only one UI thread, so you could somewhere in the Activity callback like onCreate() check and store its ID and later just compare that thread's ID to the stored one.
mMainThreadId = Thread.currentThread().getId();
Anyway, you can omit checking if you want to do something on the UI thread and have any reference to Activity by using
mActivity.runOnUiThread( new Runnable() {
#Override
public void run() {
...
}
});
which is guaranteed to run on current thread, if it's UI, or queued in UI thread.
Yes, there is a way.
Check the current thread object against main lopper's thread object. Main looper is always in the UI thread.
boolean isOnUiThread = Thread.currentThread() == Looper.getMainLooper().getThread();
Hum actually due to Android architecture, all Activities run in the main thread, ie the UI thread. So when you are coding an activity, everything that is in your Activity is in the UI thread.
That is why in Honeycomb an error have been added when you are making network calls in the main thread : it totally blocks the UI.
So by default you are in fact always working in the UI thread.
Another thing : unless you explicitely ask it to be in another thread, a Service will operate on the same thread as the activities of its application.
So, what to do ?
When you have to do heavy calculation in your activity; one solution is to use an AsyncTask (a class designed to allow you to easily use another thread). The code in onExecute() is run in another thread (but be cautious postExecute runs in your main thread). Another one is to manually start a new thread when AsyncTask is not really adapted.
If you create a service that does costly background tasks, make it run in another thread with the android:process=":my_process" attribute of the manifest. You will need to create an AIDL to communicate with this separated service, but it is not a complicated task.
Many objects, like for example the MediaPlayer, have Async variations of their methods. Try to to always use them.
Put a breakpoint where you want to check and, when it gets hit, check if you can interact with your UI (ie, if the UI is not frozen). If you can't interact with the UI then you are in the UI Thread, otherwise you are in a background thread.
In my activity, my app downloads a list of something from a website via an Http Connection. Before this list of things is displayed on the screen, I have a Loading... TextView with a little spinning ProgressBar to indicate that the data is currnetly being downloaded.
I noticed, that if I do any type of Thread.sleep() during the process of fetching the data from the web, it freezes the spinning ProgressBar.
Even if I put the method in it's own Handler Runnable so that it's on it's own thread, the animation freezing still occurs.
Is there anything I can do about this?
Yes, use AsyncTask.
A Handler is usually attached to the UI thread. Posting Runnables to it doesn't change the fact that they will run on the UI thread.
Any application should do long running tasks on a seperate thread to the UI thread as any blocking calls will not allow the UI to update.
As the other poster said, using Runnables alone do not mean the code will be executed on a seperate thread. In this case the run() method will execute on whatever thread your Handler object was created on. Either subclass Thread or pass your runnabe to new thread object with public Thread (Runnable runnable).
Using AsyncTasks, Loaders or Threads will help.
Also read Designing for Responsiveness and Multithreading For Performance. Following the above approaches will help you avoid ANRs
The reason for such a behaviour is that:
When you do thread.sleep() inside a runnable, it is the UI thread which executes that runnable rather than the respective other thread which you created. Basically what happens is that when you post any runnable through the handler of the UI thread, UI thread will poll from its queue and execute the runnable; in this case the runnable will do sleep.
Hence no change in progress bar
I have a function that takes a while and want to display a waiting screen :
Loading.showSplash("Working...");
for (FileListRow row : model.getList()) {
performAction(row);
}
Loading.hideSplash();
The problem is that the performAction(row); seems to be executed before the loading screen and hence it defeat the purpose.
Any help on solving this to force the waiting screen to show before the rest is executed and to force the function to finish before the waiting screen goes away.
Can I assume this is a Swing program?
If yes, then it looks like you're performing your long-running operations on the event dispatch thread. This is a bad idea; you should perform all long-running operations on a workert hread. See the Java tutorial for more information.
And if you do perform long-running operations on a background thread, your definitely do not want to use a semaphore to suspend the GUI thread until those operations complete -- or even until they start. The GUI thread should be allowed to run freely and dispatch events, or your UI will have "lags," which are annoying to users. As other posters have indicated, your worker thread can use SwingUtilities.invokeLater() to update the UI.
Try giving this a shot. You should call all code that does GUI updates from the Event Dispatch Thread (EDT). Swing is not thread safe.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Loading.showSplash("Working...");
}
});
new Thread(new Runnable(){
public void run(){
for (FileListRow row : model.getList())
{
performAction(row);
}
}
}).start();
Loading.hideSplash();
I'll assume you are developing a Swing application.
Read the javadoc of the SwingWorker class : http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html.
The idea is to
1. display your splash screen
2. start a thread which performs all your actions in the background.
3. when the background operations are finished, hide the splash screen
The SwingWorker takes care of this. Note however that the background operations may not use any Swing-related component or class, since they're not thread-safe and must execute in the event dispatch thread (EDT).
Another, simpler approach would be to display your splash screen, and then use SwingUtilities.invokeLater to perform your operations and hide the splash screen. This way, everything will be done on the EDT, but the splash screen will be displayed before the other operations are performed. Note however that with this technique, the application GUI will be unresponsive until the splash screen is hidden.