6

I have the following code.

As you can see the method postTestResults should return a Boolean.

Now the problem is that in postTestResults I create a inner class AsyncHttpResponseHandler and I override onSuccess and onFailure to get the result of the AsyncHttpResponseHandler.

BUT if I put return true in onSuccess and onFailure obviously it does not work, because onSuccess and onFailuremust return void.

Please how do I cope with such a scenario?

public static Boolean postTestResults(DBManager db, String mDeviceId,
    String mFirmwareVer, String mJobNo, int mTestType, Activity activity) {

    MyRestClient.post(possibleEmail, device, results, new AsyncHttpResponseHandler() {

        @Override
        public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
            return true; // does not work!              
        }

        @Override
        public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) {
            // TODO Auto-generated method stub

        }
    });

    return null;
}

enter image description here

Thanks

Lisa Anne
  • 4,482
  • 17
  • 83
  • 157

3 Answers3

10

After calling MyRestClient.post there still is no information available. At some time in the future onSuccess or onFailure is called. This asynchrone behaviour is intended, as you otherwise would have to wait for the a communication trip.

Do not return anything, or maybe true. And do the processing entirely differently, handle the logic by calling something in onSuccess/onFailure.


You could force a wait on the result (absolutely horrible) by:

final Semaphore semaphore = new Semaphore(0);
final AtomicBoolean succeeded = new AtomicBoolean();

MyRestClient.post(possibleEmail, device, results, new AsyncHttpResponseHandler() {

    @Override
    public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
        succeeded.set(true);
        semaphore.release();
    }

    @Override
    public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) {
        succeeded.set(false);
        semaphore.release();
    }
});

semaphore.aquire();
return succeeded.get();

After calling the posting, the semaphore halts the current thread's execution (because of 0 permits in its constructor). When a callback is done (onSuccess/onFailure) a result is set (succeeded).

The local variables must be (effectively) final, so their object does not change. This is as the callbacks are in another thread, and the objects referenced in the callbacks are actual copies. So for understanding the must be final. The result however must be written to, hence a value holder, internal state of a final object must be used. Hence the AtomicBoolean, as a final boolean cannot be written to.

By the way, Boolean as result if an object wrapper (Boolean.TRUE, FALSE or null), boolean seems more appropriate.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • 1
    I have this feeling. Your answer is fully correct, but it is so absolutely horrible that i can not vote it up. But still this does the job. ;-). – Damian Leszczyński - Vash Aug 26 '14 at 09:08
  • 1
    @Vash-DamianLeszczyński right, the same feeling of introducing a wait somewhere. Though it is certainly a valid control flow technique to turn something asynchrone into a synchrone wait (at the cost of waiting for that thread). Callbacks are efficient, deserve their hype in JS and so on, but are also the new "gotos". – Joop Eggen Aug 26 '14 at 10:28
  • It works, but it's not really an asynchronous call ^^ – cyril wirth Aug 28 '14 at 07:24
  • @cyrilwirth I wanted to say that the _behaviour_ of `post` is asynchrone, being called back in the future by a `onSuccess/onFailure`. At the moment I cannot find better wording. Would be pleased to read a different wording, maybe correct term. Something with event handling? Or do you mean something different. – Joop Eggen Aug 28 '14 at 08:27
  • I want to say, if you need to do an async call, do something next the call, and do something else when you've the callback this method won't work, excepted if this class is just call to do the async call. But I'm ok to say that there is no really good method to RETURN the result of an async call – cyril wirth Aug 28 '14 at 09:24
4

In your code example you use annonymous class not inner.

Annonymous class does not differ from regular classes. Its a syntax sugar that allow you to implement interfaces in place (without declaring class name, javac will do this for you).

In your case you should throw an exception in method onFailure order by interrupt the execution of code.

Because you deal with asynchronic call, you do not know when the code will be executed. There fore the task you wan to perform on success should be invoked from method onSuccess or the application should wait in some place for the result of the call back.

2

You can add a system like that :

public class MyAsync extends AsyncHttpResponseHandler{

    private final MyAsyncState state;

    public MyAsync(MyAsyncState state){
        this.state = state;
    }


    public void onSuccess(......){
        this.state.setResult(true);
    }

    public void onFailure(.....){
        this.state.setResult(false);
    }

}

An the class MyAsyncState :

public class MyAsyncState{

    private Boolean state;

    public void setResult(boolean b){
        this.state = b;
        doIt();
    }

    private void doIt(){
        // do what you want 
        // show popup for example
    }
}
  • Thanks Cyril I was looking for a way to return a value for the method that is calling the asynchronous `MyRestClient.post` but that seems not to be possible – Lisa Anne Aug 26 '14 at 08:55