Confirm dialog (Alert) inside AsyncTask - java

I have a long process running inside AsyncTask but it might need to confirm something from user while processing. I know how I can show a confirm dialog but how can I retrieve the output and keep wait till use confirms?
this.runOnUiThread(new Runnable() {
public void run() {
boolean output = ConfirmUser(message);
}
});

I will say that it is bad idea. If you need a confirmation from user, you better split your AsyncTask in two parts: do some part first, then inside onPostExecute() you can show dialog (because it is running on ui thread) and, depending on user action, launch second AsyncTask.
If you still want to do it one AsyncTask, you can do it like this:
final BlockingQueue<Boolean> queue = new ArrayBlockingQueue<Boolean>(1);
this.runOnUiThread(new Runnable() {
public void run() {
// Assuming you have ConfirmUser method which returns boolean
queue.add(ConfirmUser(message));
}
});
Boolean result = null;
try {
// This will block until something will be added to the queue
result = queue.take();
} catch (InterruptedException e) {
// deal with it
}

Related

How to avoid org.eclipse.swt.SWTException: Invalid thread access

I have a listener to an SWT button which starts like this:
button1.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
Runnable runnable = new Runnable() {
public void run() {
String nextValue = text1.getText();
...
I need the current value of the Text field called text1 in the UI, but the last line getText() fails with
org.eclipse.swt.SWTException: Invalid thread access
I know about syncExec/asyncExec (my code has several) but other threads here at StackOverflow suggest you only need to use it when you want to update a field in the UI. What is the correct way to read a UI field inside a listener?
Here are some code fragments that demonstrate how to run code synchronously & asynchronously (copied from Lars Vogel's VERY useful site).
// Update the user interface asynchronously
Display.getDefault().asyncExec(new Runnable() {
public void run() {
// ... do any work that updates the screen ...
}
});
// Update the user interface synchronously
Display.getDefault().syncExec(new Runnable() {
public void run() {
// do any work that updates the screen ...
// remember to check if the widget
// still exists
// might happen if the part was closed
}
});

Starting/Calling the same thread multiple times Java Android

I need to call the same thread multiple times in my app. Using my original code, the first time is can be executed just fine. But the second time it crashes - I then learned that each thread shall only be executed not more than one time.
My original piece of code:
View.OnClickListener myClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
mythread.start();
}
};
Thread mythread = new Thread(){
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Running...");
}
});
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Finished...");
}
});
}
};
So as I said, it crashes if I try to run it for the second time. So I tried modifying it like:
View.OnClickListener myClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
test();
}
};
private void test(){
Thread mythread = new Thread(){
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Running...");
}
});
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Finished...");
}
});
}
};
mythread.start();
}
It works very good; but my question is that whether this is the correct way to do this action or there is a more optimal way to do this?
Also, is it an acceptable thing to call a thread from insider of another thread? (like the way I put stuff on UI Thread inside the new thread of mine)
EDIT:
This is just an example. For my actual code I have heavy math-based simulation to be done which takes 10sec to be done. Based on the results that will be shown to the user , they may want to change their input parameters and let the simulation run again. This will happen several times.
In addition to the other good answers about using AsyncTask or runOnUiThread(), you could define a private member as a Runnable, like this:
private Runnable mytask = new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Running...");
}
});
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Finished...");
}
});
}
};
Then, whenever you want to run it, do
new Thread(mytask).start();
There is nothing bad with that but I think a better way would be using AsyncTask. It is exactly designed for this cases.
You can use AsyncTask multiple times just creating a new one like this new MyAsyncTask().execute(""); (source from here)
Also, is it an acceptable thing to call a thread from insider of another thread? (like the way I put stuff on UI Thread inside the new thread of mine)
runOnUiThread exists solely for that purpose. But there are usually much better ways (e.g. AsyncTask) so using this method is probably a bad idea.
my question is that whether this is the correct way to do this action or there is a more optimal way to do this?
You should not use a thread just to schedule future tasks. They are useful to execute something in parallel to the main thread but add lots of potential errors (try rotating the screen between it prints running..finished, could crash)
I would use a CountDownTimer in your case.
Or a Handler, examples e.g. here: Schedule task in android
From the provided code I assume that you want to perform an UI operation before and after your long mathematical computation. In such as #Andres suggested, AsyncTask is your best buy. It provides method onPreExecute, onPostExecute which runs on UI thread, and thus no need for explicitly calling runOnUiThread.
Key concepts :
You can't start an already started thread. This will return in an IllegalStateException. If you need to perform same task again, you should create a new instance.
If you find yourself creating several instances of a thread (even AsyncTask), since you need to run same task again and again, I would suggest you to use Thread Pool or simple Java Executor Service. Create a singleThread or may be pool and post your runnable onto executorService and it will take care of the rest.
Inter-Thread or Inter-Process communication is quite common requirement.

Java - How to use JProgressBar with SwingWorker

I am creating a Java application with a downloader. My problem is, the progress bar is not working. I want my progress bar to show the download progress but failed. Here is some part of my code. The progressbar just stuck at 0%...
Download.class
public void startDownload()
{
ExecutorService executor = Executors.newSingleThreadExecutor();
FutureTask<Void> verDownloader = new FutureTask<Void>(vd);
FutureTask<Void> launcher = new FutureTask<Void>(dd);
executor.execute(verDownloader);
executor.execute(launcher);
executor.shutdown();
}
VersionDownloader.class
public class VersionDownloader implements Callable<Void>, PropertyChangeListener
{
#Override
public Void call() throws Exception
{
done = false;
final SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>()
{
#Override
protected Void doInBackground() throws Exception
{
try
{
URL fileURL = new URL(url);
org.apache.commons.io.FileUtils.copyURLToFile(fileURL, path);
}
catch(Exception e)
{
}
return null;
}
#Override
public void done()
{
done = true;
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
};
worker.execute();
worker.addPropertyChangeListener(this);
worker.get();
}
}
}
catch(Exception e)
{
}
return null;
}
#Override
public void propertyChange(PropertyChangeEvent evt)
{
if(!done)
{
int progress_a = progress;
//launcher.frame.progress is a JProgressBar
launcher.frame.progress.setValue(progress_a);
}
}
}
Is that any code wrong?
This sort of thing is less trivial than it sounds. copyURLToFile() is going to block until the copy is completed, so that will only give you two events - 0% and 100%.
If you want to show progress while you do the download, there is one prerequisite: You must know the file length before the download starts (so you can compute percentages). You could get that - maybe - by issuing an HTTP HEAD request before starting the copy - but whether the Content-Length field is there in the response depends on the server - for chunked encoding, you don't get this information (though you might be able to force some servers to tell you by issuing an HTTP 1.0 request). Failing that, you could cheat and pick an arbitrary number of bytes.
Once you have the length or an approximation, you can either
Run a timer and periodically check the number of bytes downloaded so far, and compare that with the size, OR
Open the URL as an InputStream and do your own loop to copy the bytes, and on each loop iteration, update the progress bar
Either way, make sure you use EventQueue.invokeLater() to update the progress bar's value property or you may have deadlock issues - it is not safe to modify Swing components from any thread but the event thread.
Read the section from the Swing tutorial on How to Use Progress Bars for a working example that uses a SwingWorker.
Start with something that works and make changes for your particular requirement. If you still have problems then post a SSCCE that demonstrates the problem.

Order of execution lines of code

I don't get this :
In a ShakeListener class, I execute a routine in the containing class.
The routine is :
public void showWord(){
myShakeListener.stop();
flipper.showNext();
v.vibrate(countdown5, -1);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
myShakeListener.start();
}
Strange thing (to me, still a beginner), is that the thread sleeps BEFORE the next view is shown. Why is that?
What I want to accomplish : user shakes phone -> viewflipper flips to next -> Phone is unresponsive to shaking for 5 seconds -> user shakes phone -> viewflipper flips to next...
thnx
The problem is that the viewflipper is probably another thread. You're hitting a race condition. Better option is to spawn a thread for 5 seconds that sets a boolean called something like "noshake" to true when it starts and sets it false it when it's done. Check if noshake == false before allowing another shake.
Does that makes sense?
It's because your code is blocking the UI thread. You should do something like this:
Handler mHandler = new Handler();
public void showWord(){
myShakeListener.stop();
flipper.showNext();
v.vibrate(countdown5, -1);
mHandler.postAtTime(new Runnable() {
#Override
public void run() {
myShakeListener.start();
}
}, 5000);
}

What if I need to return an object from thread's runnable object?

What I need is to return token object as a result of adapter.authenticate() operation placed in thread. Have no idea how to return an object from there, please advice. Thank you.
public Token authenticate(final String email, final String password) {
Thread mThread = new Thread(new Runnable() {
#Override
public void run() {
try {
token = adapter.authenticate(email, password); // I need token to return with authenticate() method.
} catch (NotAuthenticatedException e) {
}
}
});
mThread.start();
}
Try this:
public Token authenticate(final String email, final String password) {
final Token[] tokens = new Token[1];
Thread mThread = new Thread(new Runnable() {
#Override
public void run() {
try {
tokens[0] = adapter.authenticate(email, password);
} catch (NotAuthenticatedException e) {
}
}
});
mThread.start();
mThread.join();
return tokens[0];
}
Explanation:
You can't make token a Token because it has to be final.
You need to join the thread, or else the authenticate is liable to return before the thread has set the token in tokens[0].
It should also be noted that you are not achieving much by using a thread in that way. What you are doing is really just an expensive way of calling adapter.authenticate(email, password).
If your aim is to avoid blocking the UI while waiting for authentication, the solution needs to be more complicated. Basically, you need to change your application so that the view elements that require authentication to have happened start out as disabled (e.g. they are greyed out / ignore clicks / whatever). You do the authentication is a separate thread as above, and when it completes you get it to send an event to the UI thread. On receiving that event, the UI thread should then enable the disabled view elements.
Implement the Callable interface. Treat the call method just like run, and you can return your token.
Why would you want to start something in another thread and then wait for the outcome? Just call adapter.authenticate() directly.
If you need to the results of an asynchronous operation in the gui, then you need to use a callback method. you need to essentially use 2 runnables. the first runnable does the work on a separate thread. when that work is complete, the result should be passed into a second runnable which is passed to SwingUtilities.invokeLater. The second runnable will be run on the EDT thread at the next available opportunity and can safely update the ui with the results of the asynchronous operation.
If you don't want the UI to freeze, you need to do something like this:
(Source is for illustration purpose only, has compile error etc. (for brevity))
class Sample {
static final Executor exec = Executors.newCachedThreadPool();
final Adapter adapter = new Adapter();
public Token processRequest(final Email email, final Password password){
Future<Token> future = exec.submit(
new Callable<Token>(){
#Override
public Token call(){
return adapter.authenticate(email, password);
}
});
//do some stuff
if(future.isDone()){
//Ah, it's done.
return future.get();
}
//Not done yet. do some more useful stuff.
//Nothing to do anymore. Just block on the future and
// wait until it's finished.
return future.get();
}
}
Or of course you can store the future somewhere associated with the session and only return when requested by the user etc.
Your authenticate() method cannot return Token (unless it can be a placeholder object) since for it to return straight away, the result may not have been discovered yet.
Have the outer object implement a callback method, something like void authenticationComplete(Token authToken) and have your Runnable call that method with the result when it arrives.
class Authenticator {
...
public void authenticate(final String email, final String password) {
new Thread(new Runnable() {
public void run() {
Authenticator.this.authenticationComplete(
adapter.authenticate(email, password)
);
}
}).start();
}
public void authenticationComplete(Token authToken) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Update your UI
}
});
}
}

Categories