Android Java runOnUiThread() - java

I have been messing around a bit with the runOnUiThread method. And if I simply make a method in my activity:
public void Test()
{
runOnUiThread(new Runnable()
{
public void run()
{
Log.v("mainActivity", "test");
}
});
}
I noticed that this runnable only runs once. However, this is not a problem. What I was wondering is if I have completely missed something and it does something in the background that would cause a frame rate drop when I have executed the method a couple times.

This is the full body from Activity.runOnUiThread(Runnable):
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
The method body is still executed in your background thread, and mHandler of class android.os.Handler implements an internal queue for Runnables posted to it, so unless you're doing blocking work in the Runnable (which is a big no-no on the UI Thread) or calling this method upwards of a thousand times in a short period, you should not see any difference.
Now, if you were calling Handler.postAtFrontOfQueue(Runnable), then there'd be an issue, because your Runnable is essentially "cutting in line". In this case, that would likely cause a stutter, because your Runnable is being executed instead of any UI updates that needed to take place (like scrolling).
Note that you only need to run UI updates on the UI thread, like calling any methods on a View (thus the name "UI Thread" and why this method exists) or any operation where the documentation explicitly states that it needs to be run on the UI thread. Otherwise, if you're already on a background thread, there's no real reason to leave it.

It's unlikely that it would cause any significant interruption to your UI process, but there's really no point in running it on the UI thread.
If you are doing any significant amount of work, you should make sure that you do not do it on the UI thread.

Related

order of execution mixed up with use of Thread.sleep

I am writing a method for my android app where I make a RecyclerView invisible, and a ProgressBar visible. I then perform some logic, before resetting the two views to their original visibility state.
With just the setVisibility() call, it works as intended. However, I am also required to call Thread.sleep() to force a wait directly after performing the logic.
Initially, I have had trouble trying to call setVisibility() to begin with. It simply did nothing. I have found many questions with similar problems, but not similar enough; I was unable to find a solution specific to my problem.
Creating a new method to simply call setVisibility(), I found that this worked as intended. I started to move my logic over, line by line, until it stopped working.
As it stands, it still technically sets the visibility correctly. However, despite being several lines down from the setVisibility() calls, my Thread.sleep() seems to be forcing itself to run before setVisibility(). I believe this was my original problem; Logically, the commands after Thread.sleep() would run directly after, and effectivley undo my setVisibility() on the very next frame.
This is my method:
public void SetMainInvisible(){
mRecyclerView.setVisibility(View.INVISIBLE);
mMainProgressBar.setVisibility(View.VISIBLE);
mTrainAdapter.RefreshAll();
Log.d("TEST", "FINISHED VIS");
try {
Thread.sleep(sSleepTime);
} catch (InterruptedException exception) {
// In the nature of a simple "Thread.sleep", there is no real reason to respond
// directly to interruption. If the sleep request is interrupted, the best course
// of action to preserve user experience is to simply move on. That said, we will
// still "re-enable" the flag that tells us the thread was interrupted, in case we
// should need to clarify if there was an interruption, later on. As is, this flag
// will be reset to false as soon as the exception is thrown.
Thread.currentThread().interrupt();
}
}
From my direct observation, when it calls, my log prints "FINISHED VIS". My application then enters the Thread.sleep() stage, and waits for 3 seconds. My views then change their visibility, as directed by the very first lines. I do not have setVisibility() anywhere else in my code.
I have tried reading further on Thread.sleep, but all references suggest exactly what I have been taught; when it executes, it forces the process to "sleep" for a set period of time. It should not force the method to postpone all other logic until it returns. On the contrary, the examples at Tutorial Point provide logic and output that suggests normal operation.
I know that I should never really be calling Thread.sleep(), but it is a direct requirement of the exercise I am completing for University. Why is Thread.sleep() forcing itself to run before any other command, despite being at the end of the method?
Changing visibility (or any other layout/drawing operation) does not have any immediate, synchronous effect on your user interface. Instead, essentially just a message is posted on the UI thread's message queue to take care of the change later.
Calling sleep() on the UI thread is a no-no. You're blocking the UI thread and execution does not return to the message handler that would take care of the relayout/redraw messages waiting in the queue. Only after the sleep() does the execution return to the message handler.
If you need to add delays to your code, use e.g. Handler#postDelayed() to post a Runnable of your own to the UI thread's message queue to be executed after a delay.
Working off #laalto's answer, I decided to test my method in the form of an AsyncTask, before looking into Handler#postDelayed() (This is something we have not covered, and I am completely unfamiliar with it). I am happy to report that it works exactly as intended.
This might be a suitable alternative, for those that are more familiar with implementing AsyncTask.
First, I implement an inner asynchronous class as follows:
private class RefreshTimesAsyncTask extends AsyncTask<Void, Void, Void> {
private long mSleepTime;
public RefreshTimesAsyncTask (long sleepTime) {
mSleepTime = sleepTime;
}
#Override
protected void onPreExecute() {
mMainProgressBar.setVisibility(View.VISIBLE);
mRecyclerView.setVisibility(View.GONE);
mTrainAdapter.RefreshAll();
}
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(mSleepTime);
} catch (InterruptedException exception) {
// ...
Thread.currentThread().interrupt();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
mMainProgressBar.setVisibility(View.GONE);
mRecyclerView.setVisibility(View.VISIBLE);
}
}
I then simply call new RefreshTimesAsyncTask(sSleepTime).execute();, rather than my previous function call of SetMainInvisible(). I also set static long sSleepTime=3000 in the variable declaration of my main class, due to the nature of being required to set this value as a static, and not being able to declare static variables in an inner class.

If you have multiple threads using runOnUiThread, are they different threads, or are they all running on one thread?

I'm new to multithreading, so excuse my potentially silly question.
I need to use several threads in my app. However, virtually all of these threads will modify the UI. I've successfully used runOnUiThread, but what I fear is that if I create different threads of the same type, they will all be running on one thread, the "Ui thread", which may slow down my app.
Is this true, or am I greatly misunderstanding?
My thread which I will essentially multiply:
private void goldPerSecondMethod() {
new Thread() {
public void run() {
while (goldCount < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
goldCount += 0.1f;
textGoldCount.setText(goldCount + " Gold");
textGoldCount.setGravity(Gravity.CENTER);
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
All help is appreciated!
I need to use several threads in my app.
Why? For example, there is no need for a thread that you create yourself in the code sample you have above. Use a postDelayed() loop (no threads), or use ScheduledExecutorService (threads, but you don't have to create them) for timing.
what I fear is that if I create different threads of the same type, they will all be running on one thread, the "Ui thread", which may slow down my app.
I have no idea what "the same type" means. In your code snippet above, everything in the Runnable that you pass to runOnUiThread() will be executed on the main application thread (sometimes called the UI thread). Everything else in your outermost run() will be executed on this background thread.
It is correct that you need to run UI updates on the UI thread. Hence you do textGoldCount.setText(...) on the UI thread. Technically, this is a correct approach.
However, it's unnecessary to call setGravity(...) every time you update the text field. You should be able to set the gravity once. Best place would be probably your XML view description.
At the end you don't do much heavy work on the UI thread, except updating the text view's text. As every thread is sleeping 1 second before updating the UI again, there should be no notable delay for the user as long as you don't run too many of those threads.

Asynchronously control the BusyIndicator

Apparently all Eclipse/SWT has in the way of managing the busy mouse indicator is
BusyIndicator.showWhile(Runnable synchronousStuffToDo)
However, I have a fundamentally event-oriented project where "stuff to do" doesn't happen within a sequential line of execution: an action gets ordered and a continuation-callback is provided to the execution manager. Therefore I have nothing meaningful to put into that synchronousStuffToDo runnable.
Is there another, however low-level and clumsy, but platform-independent way of manipulating the busy indicator asynchronously, which means two separate method calls, "activate it" and "deactivate it"?
I should add ProgressMonitorDialog to this question because it appears to suffer from the same problem. Yes, within the ProgressMonitorDialog#run method an inner event loop will be spinned, but SWT event loop is just one of my execution managers, so the chain will still be broken. Apparently without this class I can't even show a progress monitor except if I reimplement from lower-level primitives.
There is no way you can manipulate the Cursor using the BusyIndicator class.
You can invoke the below util method to show a Busy Icon while running your job on a background Thread
public static void imBusy(final boolean busy){
Display.getDefault().asyncExec(new Runnable()
{
#Override
public void run()
{
Shell shell = Display.getDefault().getActiveShell();
if(busy){ //show Busy Cursor
Cursor cursor = Display.getDefault().getSystemCursor(SWT.CURSOR_WAIT);
shell.setCursor(cursor);
}else{
shell.setCursor(null);
}
}
});
}
Your runnable should wait for the task completion. E.g. (code written in browser, will not compile - I'm ignoring exceptions):
final Object condition = new Object();
BusyIndicator.showWhile(new Runnable() {
public void run() {
synchronized(condition) {
while (!isMyTaskDoneFlag()) {
condition.wait();
}
}
}
});
doTask(new MyTask() {
public void perform() {
try {
// Task logic
...
} finally {
// When done
setMyTaskDoneFlag();
synchronized(condition) {
condition.notify();
}
}
}
});
Make sure all code paths in your tasks do not forget to unblock the runnable. Pretty much the same approach can be used with progress monitors - you may wake your runnable to update progress monitor value.
Note: You need to make sure the waiting runnable is not executed on SWT thread (e.g. set fork to true if running in progress monitor) or else your application will become unresponsive.
I found a solution (which I don't particularly like, but it works) in an older SWT application I'm working on now. It uses BusyIndicator#showWhile, and the synchronous stuff it does inside is:
Start the asynch task in a background thread
Loop waiting for the background thread to finish up while at the same time spinning the
SWT event loop explicitly:
while (!taskDone){
if (!display.readAndDispatch() && !shell.isDisposed()) {
display.sleep();
}
taskDone = //check for task progress
//update something on the main window status bar
}
I'm trying to convert this to something cleaner (along the lines of what Marko suggested):
Set the busy icon
Submit background task
Unset the busy icon
but I'm not sure what would be best for updating the status bar (background tasks are actually remote calls so their thread is blocked until they finish up). I'm thinking of having a dedicated thread that detects when background jobs are running and update the status bar accordingly (the update is just an unfolding dotted line, nothing task specific), but using a thread just for this seems a bit of a waste.

Thread Sleeping Before GUI Updating (Java 6)

public static void moveTo(Coordinate destination) {
changeState(State.NAVIGATION);
controlPnl.addRemote(Remote.createRemote(remoteType.NAVIGATION));
dmc.moveTo(destination);
changeState(State.IMMEDIATE);
controlPnl.addRemote(Remote.createRemote(remoteType.IMMEDIATE));
}
In this code, the addRemote method updates the controlPnl GUI with new buttons. The dmc.moveTo method has up to two Thread.sleep calls in it, and I think that they are being called before the controlPnl GUI is being updated. I've commented out the two method calls after dmc.moveTo which change the GUI back to what it was before the call, and the controlPnl doesn't finish updating until moveTo finishes executing. What I need is for the GUI to finish updating before the moveTo method starts executing and puts the Thread to sleep. Is there any way that I could accomplish this in Java 6?
In case it matters, the moveTo method moves a LEGO Mindstorm robot to a specified point on a path defined by the user. The GUI that is being updated provides Swing components (JButtons and JRadioButtons) for the user to control the robot with while it's navigating. The addRemote method changes the set of Swing components for the user to use, and the moveTo method sends commands to the robot to actually execute the movement (by telling its motors to move, sleeping for the correct amount of time, then telling its motors to stop moving). I'm using a state machine pattern, and this method is part of the controller which handles events from the UIs.
You have a single GUI thread. Don't use it to call other things; if you do, those things have to complete before anything else is going to happen in your GUI.
At the very least you would want to start a new thread to perform your dmc.moveTo(destination). More than likely this isn't the only place you're doing this, and probably want an Executor set up to perform these tasks.
Without knowing more about your code (especially since you're using a static method) I can't comment on how you would want to set up the Executor but the simplest example of using a Thread would be:
public static void moveTo(final Coordinate destination) {
changeState(State.NAVIGATION);
controlPnl.addRemote(Remote.createRemote(remoteType.NAVIGATION));
new Thread(new Runnable() {
public void run() {
dmc.moveTo(destination);
changeState(State.IMMEDIATE);
controlPnl.addRemote(Remote.createRemote(remoteType.IMMEDIATE));
}
}).start();
}
This creates a new Thread that executes your (anonymous) Runnable which performs your moveTo(). Note this is far less efficient than having an Executor that is ready to run your task; it has to create a new Thread every time. However, if that's not an issue in terms of the performance you need then it's perfectly fine. Also note that because I'm referencing destination directly inside the anonymous inner class, it has to be declared final when passed into your method.
Since your moveTo takes a long time you should not execute it on the main event handling thread. Instead, have moveTo update the GUI and start the actual movement in a separate thread. Once the movement is complete, use SwingUtilities.invokeLater to do the second set of GUI updates.
private static ExecutorService executor = Executors.newCachedThreadPool();
public static void moveTo(final Coordinate destination) {
changeState(State.NAVIGATION);
controlPnl.addRemote(Remote.createRemote(remoteType.NAVIGATION));
executor.execute(new Runnable() {
public void run() {
dmc.moveTo(destination);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
changeState(State.IMMEDIATE);
controlPnl.addRemote(Remote.createRemote(remoteType.IMMEDIATE));
}
});
}
});
}
This way moveTo does the initial set of GUI updates and then returns immediately, freeing the event loop to keep the GUI responsive, but the second changeState is delayed until the dmc.moveTo is complete.
(it may make more sense to factor this stuff out into separate methods rather than using the Runnable-in-a-Runnable anonymous classes)

How to figure out when I should make a function call within GUI thread

How can I know, whether I should make a function call within GUI thread.
if (SwingUtilities.isEventDispatchThread()) {
// ...
} else {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// ...
}
});
}
For example
// Should I call this within GUI thread?
jTable.getModel().setValueAt(...
Or
// Should I call this within GUI thread?
jComboBox.showPopup();
As I know, making operation in incorrect thread, may yield problem which is not easy to be detected. Hence, quite difficult for me to verify whether I am doing the correct stuff.
Currently, what I am doing is, If I am not sure, I will just call them in GUI thread
Not sure whether this is the best way, or there is a reliable way to figure out?
If you really need some ultra-generic thing "invoke ASAP" functionality, a helper like this is useful:
void invokeAsSoonAsPossible(Runnable action) {
if (SwingUtilities.isEventDispatchThread())
action.run();
else SwingUtilities.invokeLater(action);
}
// Usage:
invokeAsSoonAsPossible(new Runnable(){
#Override
public void run() {
jTable.getModel().setValueAt(...
}
});
But my experience tells me that it's a far better strategy to structure and document your code so that it gets easier to keep track of what is running where. If you've got a public method in a class which should be run on the EDT, JavaDoc is a good friend:
/**
* Blah blah blah, describe the method's purpose.
* <p>
* <strong>Note:</strong> This method should always be
* invoked on the Swing event dispatch thread.
*/
public Pony calulateValue() {
// go ahead and touch the components any way you please
}
You can also add an assertion in EDT-only methods as a kind of executable documentation:
assert SwingUtilities.isEventDispatchThread();
In short: If you have a hard time keeping track of which thread you're in, your code is probably so crufty that you have a hard time keeping track of anything, and you should worry about refactoring your code, not which thread you're on.
Actually
if (SwingUtilities.isEventDispatchThread()) {
// just do it, you're already in EDT
} else {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// ...
}
});
}
All the code that involves Swing or AWT components/classes should be run in the EDT, ie. using SwingUtilities.invokeLater(Runnable) helper.
You can configure your app using Substance Look&Feel for testing purposes. It throws an exception if UI related code is run outside of EDT.
Almost all Swing methods needs to be executed on the UI thread. There are a few exceptions (such as some setMethods). These exceptions are documented in the API docs (usually says something like "this method is thread safe"). The general rule however, is that all GUI updates should take place on the UI thread.
In most situations you should know which thread you're currently in. It's ofter quite easy to tell. All call-backs triggered by GUI events are executed on the UI thread, and the actions in the main thread and all other threads you've started are not on the UI thread.
If you however do call code from your own threads sometimes and from the UI thread other times, you could, as you've shown in your question, determine if you're on the UI thread by calling EventQueue.isDispatchThread().
I would put the code to be executed in a separate method, updateGuiComponent(...) and do
if (EventQueue.isDispatchThread())
updateGuiComponent(...);
else
SwingUtilities.invokeLater(new Runnable() { // or invokeAndWait
public void run() { updateGuiComponent(...); }
});

Categories

Resources