return String from a callback - Java

18,295

Solution 1

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.

Solution 2

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.

Share:
18,295

Related videos on Youtube

ph09
Author by

ph09

Updated on June 12, 2022

Comments

  • ph09
    ph09 about 2 years

    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;
        }
    
  • Atul Kumar
    Atul Kumar almost 6 years
    I am facing a similar problem, from the result of the callback I have to update the UI. I have adopted the same technique that you mentioned, but the problem in my case it has become cyclic like A - > B and again B -> A, where A is the UI class and B is the class that has the callBack. Is it a good practice to keep it that way or can you suggest any other alternatives? Like UI class calls the callback and callback calls the UI again.
  • Mark Peters
    Mark Peters almost 6 years
    @AtulKumar: We'd probably need some more details to know whether it's a problem. If it's causing a concrete problem, it might be appropriate to ask a question with a minimal example that reproduces the question. If you're asking generally about the design, it might be appropriate for codereview.stackexchange.com. In general I'd say mutual dependencies aren't in themselves a deal breaker, and are common in patterns like MVC (where the view and controller know about each other).