I want to update my UI from a Thread which updates a Progressbar. Unfortunately, when updating the progressbar's drawable from the "runnable" the progressbar disappears!
Changing the progressbars's drawable in onCreate() on the otherside works!
Any Suggestions?
public void onCreate(Bundle savedInstanceState) {
res = getResources();
super.onCreate(savedInstanceState);
setContentView(R.layout.gameone);
pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); //**Works**/
handler.postDelayed(runnable, 1);
}
private Runnable runnable = new Runnable() {
public void run() {
runOnUiThread(new Runnable() {
public void run()
{
//* The Complete ProgressBar does not appear**/
pB.setProgressDrawable(getResources().getDrawable(R.drawable.green));
}
});
}
}
You should do this with the help of AsyncTask (an intelligent backround thread) and ProgressDialog
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.
An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called begin, doInBackground, processProgress and end.
The 4 steps
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread immediately after 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. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. 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...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
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.
Threading rules
There are a few threading rules that must be followed for this class to work properly:
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Example code
What the adapter does in this example is not important, more important to understand that you need to use AsyncTask to display a dialog for the progress.
private class PrepareAdapter1 extends AsyncTask<Void,Void,ContactsListCursorAdapter > {
ProgressDialog dialog;
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(viewContacts.this);
dialog.setMessage(getString(R.string.please_wait_while_loading));
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
/* (non-Javadoc)
* #see android.os.AsyncTask#doInBackground(Params[])
*/
#Override
protected ContactsListCursorAdapter doInBackground(Void... params) {
cur1 = objItem.getContacts();
startManagingCursor(cur1);
adapter1 = new ContactsListCursorAdapter (viewContacts.this,
R.layout.contact_for_listitem, cur1, new String[] {}, new int[] {});
return adapter1;
}
protected void onPostExecute(ContactsListCursorAdapter result) {
list.setAdapter(result);
dialog.dismiss();
}
}
The most simplest solution I have seen to supply a short
execution to the UI thread is via the post() method of a view.
This is needed since UI methods are not re-entrant. The
method for this is:
package android.view;
public class View;
public boolean post(Runnable action);
The post() method corresponds to the SwingUtilities.invokeLater().
Unfortunately I didn't find something simple that corresponds to
the SwingUtilities.invokeAndWait(), but one can build the later
based on the former with a monitor and a flag.
So what you save by this is creating a handler. You simply need
to find your view and then post on it. You can find your view via
findViewById() if you tend to work with id-ed resources. The resulting
code is very simple:
/* inside your non-UI thread */
view.post(new Runnable() {
public void run() {
/* the desired UI update */
}
});
}
Note: Compared to SwingUtilities.invokeLater() the method
View.post() does return a boolean, indicating whether the
view has an associated event queue. Since I used the
invokeLater() resp. post() anyway only for fire and forget,
I did not check the result value. Basically you should
call post() only after onAttachedToWindow() has been called
on the view.
Best Regards
If you use Handler (I see you do and hopefully you created its instance on the UI thread), then don't use runOnUiThread() inside of your runnable. runOnUiThread() is used when you do smth from a non-UI thread, however Handler will already execute your runnable on UI thread.
Try to do smth like this:
private Handler mHandler = new Handler();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gameone);
res = getResources();
// pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); **//Works**
mHandler.postDelayed(runnable, 1);
}
private Runnable runnable = new Runnable() {
public void run() {
pB.setProgressDrawable(getResources().getDrawable(R.drawable.green));
pB.invalidate(); // maybe this will even not needed - try to comment out
}
};
Use the AsyncTask class (instead of Runnable). It has a method called onProgressUpdate which can affect the UI (it's invoked in the UI thread).
You need to create a Handler in the UI thread and then use it to post or send a message from your other thread to update the UI
If you don't like the AsyncTask you could use the observer pattern. In that example use the ResponseHandler as an inner class in your activity then have a string message that will set the progress bars percentage... You would need to make sure that any alterations to the UI are performed within the ResponseHandler to avoid freezing up the UI, then your worker thread (EventSource in the example) can perform the tasks required.
I would use the AsyncTask tho, however the observer pattern can be good for customization reasons, plus its easier to understand. Also im not sure if this way is widely accepted or will 100% work. Im downloading and the android plugin now to test it
As recommended by official documentation, you can use AsyncTask to handle work items shorter than 5ms in duration. If your task take more time, lookout for other alternatives.
HandlerThread is one alternative to Thread or AsyncTask. If you need to update UI from HandlerThread, post a message on UI Thread Looper and UI Thread Handler can handle UI updates.
Example code:
Android: Toast in a thread
Related
I recently re-imported a perfectly fine android project into Android Studio and it has unilaterally decided to complain (and red under squiggle) code that is DEFINITELY safe.
I get this red squiggle in the IDE every time (but only in postExecute):
Method publishProgress must be called from the worker thread, currently inferred thread is main thread
private void triggerClick() {
final class LoginHttpTask
extends
AsyncTask<String/* Param */, Boolean /* Progress */, String /* Result */> {
#Override
protected String doInBackground(String... params) {
publishProgress(true);
}
#Override
protected void onPostExecute(String checkPhpResponse) {
publishProgress(false);
}
}
new LoginHttpTask.execute();
}
What is the cause and why does the code run perfectly fine anyway?
This is a linting issue. From the documentation for publishProgress(Params...) (my bold):
This method can be invoked from doInBackground(Params...) to publish updates on the UI thread while the background computation is still running.
So this method is designed to only be called on a background thread, and this is reflected in the source of the method with the #WorkerThread annotation:
#WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
So while doInBackground(String...) is run on a background thread, onPostExecute(String checkPhpResponse) is run on the UI thread as you're meant to update your UI directly within that callback. Because publishProgress(Params...) is annotated as #WorkerThread, the IDE throws up an error even though the code will compile - it works, but it's bad practice.
Without any further context as to how your AsyncTask is being used I can't advise as to how to update your code, but I would advise to avoid using publishProgress(boolean) and instead update your UI directly from within onPostExecute(String)
I am working on some old android code where the code looks something like this:
public void TestMethod() {
// handler posting on main thread
handler.post(() -> {
//Invokes method();
});
animation.addListener(new AnimatatorListenerAdapter(){
#Override
public void onAnimationEnd() {
// Do some stuff;
}
});
animation.start();
}
As per my understanding, the animation life cycle callbacks always execute on UI thread. Since method() is posted first on message queue therefore it should be executed before onAnimationEnd(), but some times (3/10 times) onAnimationEnd executes before method(). Therefore now I am confused about android animation ( Surely I am missing something).
Questions:
What should be the ideal flow in this code?
Between method() and onAnimationEnd(), which one will be executed first and why?
How android animation executes on UI thread without blocking other messages and runnable in the message queue of UI Thread?
In android there is the AsyncTask which runs a thread and then i can use the method on post execute to interact with main thread again. is there an equivalent to this in java? i am trying to run a timer on separate thread (doInBackground) and once the time is finished it will then allow me to interact with the main theard to restart a service (onPostExecute will restart service)
I'm not Android developer but I think it could be easily implemented by using a CompletableFuture on Java 8:
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.CompletableFuture;
import javax.swing.SwingUtilities;
public abstract class AsyncTask <Params, Progress, Result> {
protected AsyncTask() {
}
protected abstract void onPreExecute();
protected abstract Result doInBackground(Params... params) ;
protected abstract void onProgressUpdate(Progress... progress) ;
protected abstract void onPostExecute(Result result) ;
final void publishProgress(Progress... values) {
SwingUtilities.invokeLater(() -> this.onProgressUpdate(values) );
}
final AsyncTask<Params, Progress, Result> execute(Params... params) {
// Invoke pre execute
try {
SwingUtilities.invokeAndWait( this::onPreExecute );
} catch (InvocationTargetException|InterruptedException e){
e.printStackTrace();
}
// Invoke doInBackground
CompletableFuture<Result> cf = CompletableFuture.supplyAsync( () -> doInBackground(params) );
// Invoke post execute
cf.thenAccept(this::onPostExecute);
return this;
}
}
Solution Tailored for You
In short, look at java: run a function after a specific number of seconds.
For your purpose, you don't need an AsyncTask. AsyncTask is for running something that needs the time, but you would prefer it didn't (e.g. a complex calculation or fetching data from the internet). It's for getting around the problem that you would need to wait.
What you want to do instead is to introduce a delay, or more precisely you want to schedule some action to happen after a delay. You can use a class like AsyncTask for this as well, but it's an overkill and results in more complicated code. You should instead use a class which is tailored for delayed execution, which is Timer and TimerTask:
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
// your code here
}
},
5000
);
Equivalent of AsyncTask in standard Java
Note that AsyncTask is connected to a UI concept (UI = user interface), because it may only be started from the UI thread. It's not for generally running something asynchronously.
Thus, the best matching equivalent of android's AsyncTask is SwingWorker in Java. Swing is Java's standard UI framework. It has a similar concept as android with a UI thread. In Swing, this thread is called the Event Dispatch Thread. Hence, the design of SwingWorker is also very similar to AsyncTask. Even the doInBackground() method has the same name in both classes.
Asynchronous Execution in General
If your requirement is not related to a UI and you only want to source some time consuming operation out so it executes asynchronously, then you need to look at executors. There is a variety of different ways to use executors for many different purposes, so this would go beyond the scope of this answer. If you are interested in further information, start with Jakob Jenkov's tutorial on ExecutorService.
I have a project I am working on where I need to improve my knowledge on Threads.
Scenario:
I have an Activity which calls a method Which use uses a thread:
Object soapResponse = soaphttp.fetchNextCatalogueRange(0, numberOfItems);
In the soaphttp class I have:
Thread soapThread = new Thread(new Runnable()
{
private Object serverResponse = new Object();
public void run()
{
// Do network stuff here
}
});
soapThread.start();
try
{
// crude synchronisation
soapThread.join();
}
The problem
Using join() blocks the UI thread.
If I dont use join() I get null pointer exceptions (data sync errors)
The Challenge:
In my activity I would like to do stuff on the UI thread while the soaphttp class is fetching data and then sync i.e tell the UI thread that the data is ready.
for example display a progress bar .. which will terminate when the data has finished being fetched.
How can I do this without having to use AsyncTask ?
At the very end of your thread's run() method, use one of the following:
the post() method of View class,
the runOnUiThread() method of Activity class
in order to refresh your UI in the UI thread.
You can use the same methods to somehow alter your UI at the start of the run() method (make same widgets disabled, show some kind of progress indicator...)
Because for some strange reasons, when I use AsyncTask to connect to a webpage, the UI of my app lags to almost the point of freezing while the AsyncTask is connecting to the webpage.
I thought this was because the connection usually takes quite long, at least 4 seconds.
I want to be able to update my TextView after my Thread have finished, but how do I do that in Android besides using AsyncTask?
There are a few methods to do that:
Use Threads or Runnables
Use Handlers, sending messages to its
Use RunOnUIThread method
Use the method (this is my favorite) post. It's not necessary to use a context/activity instance
For example, you can create a new Handler() and when you want to run code in the main thread do:
public static Handler interfaceHandler = new Handler();
...
mInterfaceHandler.post(new Runnable() {
#Override
public void run() {
//Your stuff
}
});
To complete the information, all Views in Android can make this post(Runnable) . This method add a runnable to their task to do, for that reason is recommendable not use views because the App will slow down. The static handler is perfect to make this work and is very easy to implement
Something like this should work
runOnUiThread(new Runnable() {
public void run() {
// do some stuff here
}
});