java swing addTaskListener - java

I am new to java and have a swing task question.
Can I add a listener to a currently running task? For instance if something happens in doInBackGround I want to add a listener for finished and display a dialog. I have tried but the compiler doesnt like me. :)
Something like.
private class MyTask extends Task<Void, Void>{
#Override
public void doInBackground(){
if(foo == foo){
this.addTaskListener(new TaskListener() {
public void taskFinsished(){}...
});
}
}
}
Thanks

Task is not a listener-oriented component. You need to override one or more of it's methods to get the results. All of these methods will execute on the EDT.
cancelled() - The cancel() method was called to terminate the task.
succeeded(T result) - The Task completed, and result holds the return value from doInBackground().
interrupted(InterruptedException e) - interrupt was called on the Thread executing the Task.
failed(Throwable cause) - The doInBackground threw an exception.
finished() - The Task has finished (in some fashion). Think of this as the functional equivalent of finally for Tasks.

Related

Is it safe to call multiple AsyncTasks within an AsyncTask and then stop the outer task if necessary?

If I did something like this:
public class MyFragment extends Fragment
{
private GetDataTask mGDT;
//onCreate() and onCreateView() are implied here
public void runTasks()
{
new TaskOne().execute();
new TaskTwo().execute();
new TaskThree().execute();
}
public class GetDataTask extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... params)
{
runTasks();
}
}
#Override
public void onResume()
{
super.onResume();
mGDT = new GetDataTask();
mGDT.execute();
}
#Override
public void onDestroy()
{
super.onDestroy();
mGDT.cancel(true);
}
}
Would calling mGDT.cancel(true) in onDestroy() end the individual AsyncTasks running in runTasks()? What is the best way to achieve something like this? I have multiple bots that will be gathering data from the web and I want each one on its own thread and I need to be able to cancel all of them if the fragment or activity is destroyed. I'm new to Android programming and multithreading so I'm not familiar with the best ways to do this type of multithreading.
That's complicated.cancel() interrupts the thread that's running (the thread that will run doInBackgroundImpl()). If the outer task's doInBackgroundImpl() hasn't run yet, it won't run. However, if it's already run or in the middle of running, it's going to run unless you explicitly look for the interrupted flag,
#Override
protected Void doInBackground(Void... params)
{
if (!Thread.isInterrupted()) {
runTasks();
}
}
And of course if the code execution of the thread has already passed the conditional interrupted check, it's going to call runTasks().
Now, if runTasks() does execute(), canceling the outer task won't effect the execution of the inner tasks. Once they are executed, they are placed on AsyncTask's executor queue and will be executed when previous task is completed (or right away if the queue is empty).
Takeaways,
1) Each executed task is independent. There's no notion of a subthread or anything like that. You have to explicitly cancel each task. The fact that one task is started by another task has no bearing on the semantics of cancel().
2) You simply can't stop a thread cold. It's why Thread.stop() is deprecated since Java 1.2 or something. All you can do is mark it interrupted, then either hope the code you use in the thread respects isInterrupted(), or write your own code to respect it.
In your case, if your goal is to cancel all subtasks when the parent task is canceled, you can do something like,
#Override
public void cancel(boolean interrupt) {
super.cancel(interrupt);
task1.cancel(interrupt);
task2.cancel(interrupt);
...
}

Do multiple tasks while running code in actionperformed java

Let's say i have a listener attached to a button. When i press this button, actionPerformed is called and i set a label as visible. Then the calculate() method runs(which has some really long calculations inside it and it takes time). Then i wanna print the results with the show() method.
Thing is that i know for a fact that the label will be set as visible after all the code inside actionPerformed will be executed.
So my question is : How should i set the calculate method to run on background? Threads? SwingTimer? SwingWorker? I haven't found an ideal way yet.
class ButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
calculateLbl.setVisible(true);
calculate();
show();
}
}
Your problem is one of Swing concurrency: When calculate() is called on the Swing event thread, the long-running code hampers the event thread, preventing it from painting to the JLabel. The solution is to run calculate in a background thread, and then be notified when it is done. When notification occurs, call show(). A SwingWorker would work great for this since it comes with its own notification mechanism.
e.g.,
#Override
public void actionPerformed(ActionEvent e) {
calculateLbl.setVisible(true);
new SwingWorker<Void, Void>() {
public Void doInBackground() throws Exception{
calculate(); // this is run in a background thread
// take care that calculate makes no Swing calls
return null;
}
protected void done() {
show(); // this is run on the Swing event thread
}
}.execute();
}
Caveat: code not tested/compiled/nor run.
A problem with the above code is that it does not handle any exceptions that might be thrown within the calculate method, and a cleaner better way to do this is to create a SwingWorker variable, attach a PropertyChangeListener to it, and when its SwingWorker.StateValue is SwingWorker.StateValue.DONE, call get() on the SwingWorker and handle any possible exceptions there.

How return a result of my method executed in thread?

I've a method who return a result (return an integer), my method is executed in a Thread for load 40 000 objects, i return an integer who count the number objects loaded. My question is, How return the int with the Thread ? Actually, the result is returned directly and is equal to 0.
public int ajouter(params) throws DaoException, ConnectException {
final ProgressDialog dialog = ProgressDialog.show(mActivity, "Title",
"Message", true);
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
dialog.dismiss();
}
};
Thread t = new Thread() {
public void run() {
try {
Str_Requete = "SELECT * FROM Mytable";
ResultSet result = ExecuteQuery(Str_Base, Str_Requete);
Index = addObjects(result);
handler.sendEmptyMessage(0);
} catch (SQLException e) {
e.printStackTrace();
}
}
};
t.start();
return Index;
}
When i call my method in my mainActivity :
int test = myObjs.ajouter(params);
test is equal to 0, the value is returned directly...
My constraint is didnt use AsyncTask.
The whole point of using a Thread is not to block the calling code while performing the task of the thread. Thread.start() returns immediately, but in the meantime a new thread is started in parallel to the current thread which will execute the code in the run() method.
So by definition there is no such thing as returning a value from a thread execution. You have to somehow send a signal back from the thread that performed the task to the thread in which you need the result. There are many ways of doing this, there's the standard Java wait/notify methods, there is the Java concurrency library etc.
Since this is Android, and I assume your calling code is running on the main thread, it's probably wise to use the functionality of Handler. And in fact, you are already doing that - you have a Handler that closes the dialog when the thread is done with its work - but for some reason you seem to expect the result of that work to be ready before it has even started. It would be reasonable to extend your existing Handler with some code that does something with the calculated value and remove the code that returns the value of a variable before or at the same time as it's being calculated by another thread.
I also strongly encourage you to study some concurrency tutorial such as Oracle's concurrency lesson or Android Thread guidelines to really understand what's going on in the background. Writing concurrent code without mastering the concepts is bound to fail sooner or later, because it's in the nature of concurrency that multiple things are happening at the same time, will finish in random order etc. It may not fail often, but you will go crazy wondering why something that works 90% of the time suddenly fails. That's why topics such as atomicity, thread synchronization etc are critical to comprehend.
Edit: Simple Android example of starting a worker thread, performing some work, posting back event to main thread.
public class MyActivity extends Activity {
private Handler mHandler = new Handler();
...
private void doSomeWorkInBackground() {
new Thread() {
public void run() {
// do slow work, this may be blocking
mHandler.post(new Runnable() {
public void run() {
// this code will run on main thread,
// updating your UI or whatever you need.
// Hence, code here must NOT be blocking.
}
});
}
}.start();
// This code will be executed immediately on the main thread, and main thread will not be blocked
}
You could in this example also use Activity.runOnUiThread(Runnable).
Please consider however that AsyncTask basically wraps this kind of functionality in a very convenient way, so if it suits your purposes you should consider using AsyncTask.
If you dont want to use AsyncTask or ForkJoin, then you could implement an Interface e.g. callback in your main class.
In your Example you dont wait until the Thread is done... thread.join
One Solution:
Your Thread is a extra class with an constructor to hold the reference to the calling class.
public Interface callback
{
public int done();
}
public class main implements callback
{
...
CustomThread t = new CustomThread(this)
...
}
public class CustomThread extends Thread
{
private Callback cb;
public CustomThread(Callback cb)
{
this.cb=cb;
}
.
.
.
//when done
cb.done(int)
}

How do I wait for a SwingWorker's doInBackground() method?

Say I have the following code:
import java.lang.InterruptedException;
import javax.swing.SwingWorker;
public class Test
{
private JDialog window;
public Test
{
// instantiate window
}
private class Task extends SwingWorker<Void, Void>
{
public Void doInBackground()
{
try { Thread.currentThread().sleep(5000); }
catch(InterruptedException e) {}
return null;
}
}
public void doTask()
{
Task task = new Task();
task.execute();
}
protected void process()
{
// update various GUI components here
}
public static void main(String args[])
{
Test t = new Test();
t.doTask();
System.out.println("done");
}
}
I need to wait until t.doTask() is done before printing out 'done', but I'm not sure exactly how. I know I should probably use join() here, but I need a thread to call it on, and I don't know how to get doInBackground()'s thread from where I need to call join(). Thanks for any help.
EDIT: Thanks for the responses. Unfortunately, get() and the like don't quite solve the problem. In my actual code, the SwingWorker also has an overridden process() function that updates a GUI window while the background thread is running. get() does stop 'done' from being printed till after doInBackground, but then the GUI doesn't update. I updated my sample code to reflect this, although now of course it won't compile.
Is there a way to get 'done' to print only once doInBackground is finished? Are the GUI update code and the 'done' statement on the same thread? Do I need to make a new thread?
Typically anything that needs to be done after a SwingWorker completes its background work is done by overriding the done() method in it. This method is called on the Swing event thread after completion, allowing you to update the GUI or print something out or whatever. If you really do need to block until it completes, you can call get().
NB. Calling get() within the done() method will return with your result immediately, so you don't have to worry about that blocking any UI work.
Calling get() will cause the SwingWorker to block.
From the Javadocs:
T get()
Waits if necessary for the computation to complete,
and then retrieves its result.
Your code will then look like:
public static void main(String args[])
{
Test t = new Test();
t.doTask();
t.get(); // Will block
System.out.println("done");
}
You can override the done() method, which is called when the doInBackground() is complete. The done() method is called on EDT. So something like:
#Override
protected void done() {
try {
super.get();
System.out.println("done");
//can call other gui update code here
} catch (Throwable t) {
//do something with the exception
}
}
Calling the get() method inside the done helps get back any exceptions that were thrown during the doInBackground, so I highly recommend it. SwingWorker uses Callable and Future internally to manage the background thread, which you might want to read up on instead of trying the join/yield approach.
In general, you must hold onto the SwingWorker until it finishes, which you can test by calling isDone() on it. Otherwise just call get() which makes it wait.

onPostExecute not called after completion AsyncTask

For some reason my onPostExecute() is not called after my AsyncTask finishes.
My class decleration:
public class setWallpaperForeground extends AsyncTask<String, Integer, Boolean>
My onPostExecute():
protected void onPostExecute(Boolean result)
Everything works fine, my doInBackground() completes successfully and returns a Boolean but then it just finishes.
Thanks
Did you start the task with execute() method? The onPostExecute wouldn't run if you just invoke the doInBackground.
Did you create your AsyncTask on the UI thread? Also add an #Override annotaiton on your onPostExecute() method to make sure you declared it correctly.
Found/Made another nasty mistake:
If your params of onPostExecute(Param param) don't match the one you defined with extends AsyncTask<...,...,Param> and you didn't use the #Override annotation, it will never be executed and you don't get a warning from Eclipse.
Note to myself:
Just always use the #Override annotation and Eclipse will help you.
Another easy way to avoid all named mistakes:
in Eclipse: Right-click in code > Source > Override/Implement Methods
After having the same problem and none of these answers helped me, I found out that my UI thread was blocked (I used a CountDownLatch.await()) and therefore the onPostExecute() method that is supposed to be called by the UI thread was never called.
Made another nasty mistake that can result in this same error. When defining the AsyncTask and calling it, I was not calling execute but was calling doInBackground
new AsyncTask<String,Void,Void>() {
....
}.doInBackground("parameter");
rather than
new AsyncTask<String,Void,Void>() {
....
}.execute("parameter");
I have faced the same problem. None of the above solutions worked for me. Then i figured out the problem maybe it helps someone else .
In UI thread i call the following codes:
public class XActivity ...{
onCreate(){
....
new SaveDrawingAsync(this).execute();
while(true)
{
if(MandalaActivity.saveOperationInProgress){
continue;
}
super.onBackPressed();
break;
}
...
}
}
My AsyncTask class definition :
public class SaveAsync extends AsyncTask<Object, Void, Void> {
#Override
public Void doInBackground(Object... params) {
saveThem(); // long running operation
return null;
}
#Override
public void onPostExecute(Void param) {
XActivity.saveOperationInProgress = false;
}
#Override
public void onPreExecute() {
XActivity.saveOperationInProgress = true;
}
}
in the above code onPostExecute is not called. It is because of an infinite loop after asynctask execution .
asynctask and inifinite loop both waits eachother to finish. Thus the code stucks!
The solution is changing the design!
I had the same behaviour, and the cause was that I have been posting a lot of messages as a progress inside doInBackground with following code:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// .. some UI updates
}
});
this must have overloaded main thrad message queue, and caused long delay before onPostExecute would get called. The solution was to post only once every second.
For me it was user error. I was ending the AsyncTask by invoking cancel(true) on it and not reading the documentation closely enough to know that onPostExecute is not called in this case, onCancelled is.

Categories