I'm trying to override the process() method to ensure that some code runs in the EDT. I have made sure that <T,V> are matching throughout but it still won't let me override. Here is my code:
final SwingWorker<ArrayList<Block>,Integer[]> swingSlaveLabourer = new SwingWorker<ArrayList<Block>, Integer[]>() {
#Override
protected ArrayList<Block> doInBackground() throws Exception {
blockList.doHeavyWork()..
Integer [] status = new Integer[2];
status[0] = 1;
status[1] = 0;
this.process(status);
return blockList;
}
#Override //wont allow override
protected void process (Integer[] chunks){
progressBar.setValue(chunks[0]);
}
};
The process method takes a List<V> as argument. It represents all the data chunks that were published. You need to change your code to:
#Override
protected void process(List<Integer[]> chunks) {
// do something
}
You should not call directly process from the doInBackground method. Instead, you should call publish to publish each chunk of data.
Refer to the following example taken from the SwingWorker Javadoc:
class PrimeNumbersTask extends SwingWorker<List<Integer>, Integer> {
PrimeNumbersTask(JTextArea textArea, int numbersToFind) {
//initialize
}
#Override
public List<Integer> doInBackground() {
while (! enough && ! isCancelled()) {
number = nextPrimeNumber();
publish(number); // each computed number is published
setProgress(100 * numbers.size() / numbersToFind); // and progress updated
}
}
return numbers;
}
#Override
protected void process(List<Integer> chunks) {
// in the mean while, we print each published value to a textarea
for (int number : chunks) {
textArea.append(number + "\n");
}
}
}
Related
I'm using a SwingWorker to execute some repeatable tasks in background.
This is my Class:
public class CMyThread {
private SwingWorker<Object, Void> taskWorker;
public volatile boolean threadDone = false;
public CMyThread() {
}
#Override
public void stop() {
taskWorker.cancel(true);
}
#Override
public void start() {
taskWorker = new SwingWorker<Object, Void>() {
#Override
public Object doInBackground() {
while (!isCancelled()) {
// SOMETHING TIMECONSUMING THAT NEEDS TO BE DONE REPEATEDLY
CUtils.sleep(10000);
}
threadDone = true;
return null;
}
#Override
public void done() {
}
};
taskWorker.execute();
}
public void waitThreadToGentlyFinish() { // called when we call destroy() on the servlet
while (!threadDone) {
System.out.print("#");
CUtils.sleep(200);
}
}
}
And this is called this way:
CMyThread myThread = new CMyThread();
myThread.start();
Now, at one point I want to gently stop the thread.
So I call
myThread.stop();
myThread.waitThreadToGentlyFinish();
I'm expecting that the currently running [ACTION] is going to take time to finish, then only it will exit the loop and set the flag 'threadDone' to true. but what I actually see is that it exits the loop immediately and I never see any '#' characters displayed.
There is obviously something wrong in my code but I can't see the obvious.
Any idea guys ?
I have a set of APIs which are implemented using AsyncTask. Some of them have different signature( Some have progress reporting, some others have different datatype being sent as Params). But, all of these APIs return a boolean Result. On success, app Logic for successful calling of API is done. On failure, a generic error popup with error message is shown. Now I want to derive a class from AsyncTask in such a way that it implements a function onSuccessResult as well as overrides a function onFailureResult.
//I get error Params, Progress not recognized.
public class ServerAPIAsyncTask extends AsyncTask<Params, Progress, Boolean>{
abstract public void onSuccessResult();
public void onFailureResult() {
int err = getErrorCode();
showPopup(err);
}
#override
protected void onPostExecute(final Boolean success) {
if (success)
onSuccessResult();
else
onFailureResult();
}
}
Please note that I have to do all of this with two generic datatypes Params and Progress. How can I achieve this? I want to achieve this for two reasons. First I want to derive from this new class like this:
public class getCarDetailAPITask extends ServerAPIAsyncTask<Garage, void, Boolean> {
#Override
protected Boolean doInBackground(Void... params) {
//call my api
}
#Override
protected void onPostExecute(final Boolean success) {
super.onPostExecute(success);
}
#Override
public void onFailureResult() {
super.onFailureResult();
}
#Override
public void onSuccessResult() {
//Do app logic
}
}
Secondly, it helps me to keep the onFailureResult logic at one place thus, not repeating it over and again.
For Params, Progress and Result you need to pass in actual classes when you extend AsyncTask. Since you don't have classes in your class-path that match the names Params and Progress you get these errors.
public class ServerAPIAsyncTask extends AsyncTask<Void, Void, Boolean>{
abstract public void onSuccessResult();
public void onFailureResult() {
int err = getErrorCode();
showPopup(err);
}
protected void onPostExecute(final Boolean success) {
if (success)
onSuccessResult();
else
onFailureResult();
}
}
For your second AsyncTask you should extend AsyncTask, not your own derived ServerAPIAsyncTask. Also, the first Parameter Garage needs to match the parameter you pass into doInBackground, see below:
public class GetCarDetailAPITask extends AsyncTask<Garage, Void, Boolean> {
#Override
protected Boolean doInBackground(Garage... params) {
//call my api
}
protected void onPostExecute(final Boolean success) {
super.onPostExecute(success);
}
#Override
public void onFailureResult() {
super.onFailureResult();
}
#Override
public void onSuccessResult() {
//Do app logic
}
}
According to your comment, there you have generic AsyncTask example:
public class MyAsyncTask<A,B> extends AsyncTask<A, Void, B> {
#Override
protected B doInBackground(A... params) {
return null;
}
// Other methods
}
You said this
//I get error Params, Progress not recognized.
public class ServerAPIAsyncTask extends AsyncTask<Params, Progress, Boolean>
Params and Progress are not real classes. They need to be real classes present in your package.
Some of them have different signature( Some have progress reporting, some others have different datatype being sent as Params).
Different datatype being sent as param? So set params to Object type. It is the superclass of all classes.
See this example, taken from AsyncTask documentation itself:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
I am working on java swing with some multithreaded application. The situation is so, that I need to execute one thread after another i.e I output of one is related to the second. I did the following.
// Class one
public class Samp implements Runnable{
public Samp(String name) {
this.setName = name;
}
public void run (){
// Here I have a file extraction method called
extract(this.getName);
}
// Extract Method
public Boolean extract(String filename){
// Some extraction Operation.
// I want to update the jTextField with the current filename under extraction.
}
}
// the GUI Class
public class Welcome extends javax.swing.JFrame {
SwingWorker<Boolean, Void>worker = new SwingWorker<Boolean, Void>() {
#Override
protected Boolean doInBackground() throws Exception {
Thread t1 = new Thread(new ZipUtility(fileName));
t1.start();
return true;
}
// Can safely update the GUI from this method.
#Override
protected void done() {
// Here when this worker is done I wanted to Run worker 2
}
};
SwingWorker<Boolean, Void>worker2 = .........
// Again when worker2 is done I wanted to run worker 3 and so on.
}
My Questions are :
1) How to run all the workers in a perfect sequencial order. i.e when worker1 is done then start worker 2, when worker2 is done then start worker 3 and so on.
2) How to update a textfield in my Welcome class, with the values from the Samp class.
Thanks in advance.
1) How to run all the workers in a perfect sequencial order. i.e when worker1 is done then start worker 2, when worker2 is done then start worker 3 and so on.
A little trick to remember, you can put a SwingWorker into a ExecutorService
So, using something like...
public static class Worker extends SwingWorker {
private int sequence;
public Worker(int sequence) {
this.sequence = sequence;
}
#Override
protected Object doInBackground() throws Exception {
System.out.println(sequence + "...");
Thread.sleep(500);
return null;
}
}
As a test, you could use something like...
ExecutorService es = Executors.newFixedThreadPool(1);
for (int index = 0; index < 10; index++) {
es.submit(new Worker(index));
}
es.shutdown();
(You don't need to call shutdown, but otherwise my tested never allowed the JVM to terminate ;))
Which will run the workers in the order they are submitted.
Now, if you want to feed the values from one SwingWorker to another, you could do something like...
public abstract class ChainedWorker<T, V> extends SwingWorker<T, V> {
private ChainedWorker<T, ?> next;
private T previousValue;
public ChainedWorker(ChainedWorker<T, ?> next) {
this.next = next;
}
public void setPreviousValue(T previousValue) {
this.previousValue = previousValue;
}
#Override
protected void done() {
try {
T previous = get();
if (next != null) {
next.setPreviousValue(previous);
next.execute();
}
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
}
}
Which is simply a SwingWorker which allows you to provide a link in the chain (the next worker to call), which passes the value that this SwingWorker generated...or some such similar
Now, if you're really nuts and want to role your own, maybe something like...
public class ChainedWorkerBuilder {
private List<SwingWorker> workers;
private SwingWorker current;
public ChainedWorkerBuilder() {
workers = new ArrayList<>(25);
}
public ChainedWorkerBuilder add(SwingWorker worker) {
workers.add(worker);
return this;
}
public void execute() {
if (!workers.isEmpty()) {
SwingWorker worker = workers.remove(0);
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("state".equals(evt.getPropertyName())) {
SwingWorker source = (SwingWorker)evt.getSource();
switch (source.getState()) {
case DONE:
source.removePropertyChangeListener(this);
execute();
break;
}
}
}
});
}
}
}
2) How to update a textfield in my Welcome class, with the values from the Samp class.
I don't think I'm following your code directly, but, if you did something like...
SwingWorker<Boolean, Void>worker = new SwingWorker<Boolean, String>() {
protected Boolean doInBackground() throws Exception {
publish(fileName);
ZipUtility zu = new ZipUtility(fileName));
return zu.extract(fileName);
}
Then in the SwingWorkers process method you would be able to update the UI safely...
#Override
protected void process(List<String> chunks) {
// Grab the last element...
textfield.setText(chunks.get(chunks.size() - 1));
}
}
Simply call execute() on worker2 from worker1's done:
final SwingWorker<Boolean, Void> worker2 = new SwingWorker<Boolean, Void>() {
...
}
final SwingWorker<Boolean, Void> worker1 = new SwingWorker<Boolean, Void>() {
#Override
protected Boolean doInBackground() throws Exception {
// Don't start a thread, do your work, otherwise the done will fire
// too early, also it's pointless to use worker and thread like that
return true;
}
// Can safely update the GUI from this method.
#Override
protected void done() {
// update some ui
// and start the second part
worker2.execute();
}
};
I have following code for a chat server application in Java -
public synchronized List<ChatMessage> getMessages(int messageNumber) {
return messages.subList(messageNumber + 1, messages.size());
}
public synchronized int addMessage(ChatMessage c) {
messages.add(c);
return messages.size()-1;
}
I have following test code -
public static void main(String[] args) {
final ChatRoom c = new ChatRoom();
Thread user1 = new Thread(new Runnable() {
public void run() {
for(int i=0;i<1000;i++) {
c.addMessage(new ChatMessage());
c.getMessages(0);
}
}
});
Thread user2 = new Thread(new Runnable() {
public void run() {
for(int i=0;i<1000;i++) {
c.addMessage(new ChatMessage());
c.getMessages(0).size();
}
}
});
user1.start();
user2.start();
}
I am getting a ConcurrentModificationException.
How is this possible?
How is this possible?
Your getMessages method just returns a view on the original list. It doesn't create a copy of the list. So one thread is using a view on the list while another modifies the list - at that point, you get the exception.
From the docs for List.subList:
The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)
It's not clear what you're really trying to achieve here, but fundamentally you can't use subList to magically create a thread-safe list :)
The simplest thing to do is to create a combined method
public synchronized int addMessageAndGetCount(ChatMessage c) {
messages.add(c);
return messages.size();
}
public static void main(String... args) {
final ChatRoom c = new ChatRoom();
final Runnable runner = new Runnable() {
public void run() {
for(int i = 0; i < 1000; i++) {
c.addMessageAndGetCount(new ChatMessage());
}
}
};
new Thread(runner).start();
new Thread(runner).start();
}
You cannot safely return a list or a subList from a synchronized block. You can return a copy but all you need is the size.
does anyone know how I can solve the following problem. I want to return a String from a callback, but I get only "The final local variable s cannot be assigned, since it is defined in an enclosing type", because of final.
public String getConstraint(int indexFdg) {
final String s;
AsyncCallback<String> callback = new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
public void onSuccess(String result) {
s = result;
}
};
SpeicherService.Util.getInstance().getConstraint(indexFdg, callback);
return s;
}
The whole point of an asynchronous callback is to notify you of something that happens asynchronously, at some time in the future. You can't return s from getConstraint if it's going to be set after the method has finished running.
When dealing with asynchronous callbacks you have to rethink the flow of your program. Instead of getConstraint returning a value, the code that would go on to use that value should be called as a result of the callback.
As a simple (incomplete) example, you would need to change this:
String s = getConstraint();
someGuiLabel.setText(s);
Into something like this:
myCallback = new AsyncCallback<String>() {
public void onSuccess(String result) {
someGuiLabel.setText(result);
}
}
fetchConstraintAsynchronously(myCallback);
Edit
A popular alternative is the concept of a future. A future is an object that you can return immediately but which will only have a value at some point in the future. It's a container where you only need to wait for the value at the point of asking for it.
You can think of holding a future as holding a ticket for your suit that is at the dry cleaning. You get the ticket immediately, can keep it in your wallet, give it to a friend... but as soon as you need to exchange it for the actual suit you need to wait until the suit is ready.
Java has such a class (Future<V>) that is used widely by the ExecutorService API.
An alternative workaround is to define a new class, called SyncResult
public class SyncResult {
private static final long TIMEOUT = 20000L;
private String result;
public String getResult() {
long startTimeMillis = System.currentTimeMillis();
while (result == null && System.currentTimeMillis() - startTimeMillis < TIMEOUT) {
synchronized (this) {
try {
wait(TIMEOUT);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return result;
}
public void setResult(String result) {
this.result = result;
synchronized (this) {
notify();
}
}
}
Then change your code to this
public String getConstraint(int indexFdg) {
final SyncResult syncResult = new SyncResult();
AsyncCallback<String> callback = new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
public void onSuccess(String result) {
syncResult.setResult(result);
}
};
SpeicherService.Util.getInstance().getConstraint(indexFdg, callback);
return syncResult.getResult();
}
The getResult() method will be blocked until setResult(String) method been called or the TIMEOUT reached.