29

My android app connects to my website to retrieve and upload information so I use an AsyncTask thread.

In one instance, I need my thread to return a true or a false value to my main thread.

Is there a way to get this return value from an AsyncTask execute function?

When I do the following:

Toast.makeText(Locate.this, "Testing : "+locationUpdate.execute(location), Toast.LENGTH_LONG).show();

I just get alot of gibberish.

I think what I need is a means to pause the main thread until the second thread completes. The second thread calls a function in the main thread to set my return value. So when the second thread completes, the main thread can unpause and access the return value as set by the second thread If this logic is sound, please offer suggestions ... thanks!

sisko
  • 9,604
  • 20
  • 67
  • 139

4 Answers4

41

You can use AsyncTask get() method for this. It waits if necessary for the computation to complete, and then retrieves its result:

Toast.makeText(Locate.this, "Testing : " + locationUpdate.execute(location).get(), Toast.LENGTH_LONG).show();

But be sure to not block the main thread for a long period of time, as this will lead to unresponsive UI and ANR.

UPDATE
I missed the point that question was about async web download/upload. Web/network operation should considered as a long one and thus the approach "pause UI thread and wait till download finishes" is always a wrong one. Use usual result publishing approach intstead (e.g.: AsyncTask.onPostExecute, Service + sendBroadcast, libraries like Volley, RoboSpice, DataDroid etc).

Volo
  • 28,673
  • 12
  • 97
  • 125
  • 8
    don't use get!!! it freezes the UI. http://stackoverflow.com/questions/9019249/progressdialog-not-shown-when-asynctask-get-called (this happened to me so I am posting this where I originally found the suggestion) – aldo.roman.nurena Dec 01 '12 at 00:05
  • @aldo.roman.nurena Read the last sentence of my answer: `be sure to not block the main thread for a long period of time, as this will lead to unresponsive UI and ANR`. If AsyncTask execution takes over 200msec this approach is certainly not the best choice and usual result publishing (with `AsyncTask.onPostExecute`) should be used instead. Btw, there is also more flexible version of [`AsyncTask.get()`](http://d.android.com/reference/android/os/AsyncTask.html#get%28long,%20java.util.concurrent.TimeUnit%29) method which allows you to specify maximum period of time to wait for the AsyncTask. – Volo Aug 27 '13 at 08:50
  • In the case of this question, it connects to a website and download data. That is always a long period, at least long enough for the user to notice and that is a bad pattern. Giving a timeout parameter may crush the app if the downloaded data is necessary for the execution. – aldo.roman.nurena Aug 28 '13 at 16:40
  • 1
    @aldo.roman.nurena You're right about web download, it's a long term task (guess I missed the OP was asking about async **web** operation) - usual result publishing approach should be used for that (using AsyncTask.onPostExecute, Service or library like Volley). I've updated the answer. But just to clarify (outside of the question scope) - I can't see how `timeout parameter may crush the app`. In case of timeout a `TimeoutException` is thrown, since it's checked one you have to catch it and provide some "timeout-happened" logic. – Volo Aug 29 '13 at 08:48
  • In my app (a Dropbox-like-app), I needed to download files contained in a folder so user can open them. If "clicked" but now downloaded, the app crashed as the view received no data. You're right, the exception is a great solution. – aldo.roman.nurena Aug 29 '13 at 22:24
4

Handler is the best way to do this in onPostExcecute() method simply do

@Override
    protected void onPostExecute(Boolean bool) {
        super.onPostExecute(bool);
           Message msg=new Message();
            msg.obj=bool;
            mHandler.sendMessage(msg);
        }
    }

and your message handler will be

mHandler = new Handler() { 
    @Override 
    public void handleMessage(Message msg) { 
        bool i=(String)msg.obj;
    }
 };
Aniket Thakur
  • 66,731
  • 38
  • 279
  • 289
Sunil Pandey
  • 7,042
  • 7
  • 35
  • 48
  • 7
    Using a handler in this case is simply unnecessary. You send the returning value with a handler to (possibly) UI but you can access the UI in `onPostExecute()` by simply calling a method that uses the boolean and updates the UI (mostly dismiss the dialog and update the view content). You do it more complicated that it should be... – WarrenFaith Mar 28 '11 at 11:11
  • I tried your approach but my boolean value does not change until my asyncTash finishes. Meanwhile, the main thread continues executing when I actually require it to wait for the right return value. – sisko Mar 29 '11 at 21:55
1
public class RunWebScript {
String mString;
public RunWebScript(String url){
    try {   
        URL updateURL = new URL(url);  
        URLConnection conn = updateURL.openConnection(); 
        // now read the items returned...
        InputStream is = conn.getInputStream();  
        BufferedInputStream bis = new BufferedInputStream(is);  
        ByteArrayBuffer baf = new ByteArrayBuffer(50);  
        int current = 0;  
        while((current = bis.read()) != -1){  
            baf.append((byte)current);  
        }   
        String s = new String(baf.toByteArray());
         mString = s;
    } catch (Exception e) {  
        Log.e("ANDRO_ASYNC", "exception in callWebPage",e); 
        mString = "error";
    }
}
public String getVal(){
    return mString;
}   

}

this is executed as... (showing teh end of a method in teh calling class

        asyncWebCall (url1,CONSTANT);
}
private void asyncWebCall(String url,int actionPostExecute){
    new WebCall().execute(url,String.format("%d",actionPostExecute));
}   

The Async part of the business is ... Note the case statement in onPostExecute this is the key to getting the returned value ito your program again. Note that the call new WebCall().execute(url,String.format("%d",actionPostExecute)); is the last thing done in a thread, no further statements can be executed, control returns through the onPostExecute.

class WebCall extends AsyncTask<String, String, String>{
    int chooser = -1;
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    @Override   
    protected String doInBackground(String... params) {
        try {
            chooser = Integer.parseInt(params[1]);
        } catch(NumberFormatException nfe) {
            Log.d("ANDRO_ASYNC",String.format("asyncReturn() mString numberformatexception = %s",params[1]));
            chooser = 0;
        }
        return(new RunWebScript(params[0])).getVal();           
    }
    protected void onProgressUpdate(String... progress) {       
    }
    @Override
    protected void onPostExecute(String gotFromDoInBkgnd) {
        Log.d("ANDRO_ASYNC",String.format("chooser = %s",chooser));
        switch (chooser){
        case CONSTANT:
            printStringx(gotFromDoInBkgnd);
            asyncWebCall(url2,5); 
            break;
        case 0:
            Log.d("ANDRO_ASYNC",String.format("case 0 = %s",gotFromDoInBkgnd));
            break;
        case 5:
            Log.d("ANDRO_ASYNC",String.format("case 5 = %s",gotFromDoInBkgnd));
            asyncWebCall(url3,7);

            break;

        default:
            Log.d("ANDRO_ASYNC",String.format("man we got problems = %s",gotFromDoInBkgnd));
            break;
        }
    }

} // end of class

user462990
  • 5,472
  • 3
  • 33
  • 35
0

Here is a complete example of the issue of returning values from an async task. It may occur that there are many tasks to be done one after the other asynchronously.

Basics. 1. get a return value from a class.

public class Snippet {
int computVal;
public Snippet(){
    computVal = 17*32; 
}
public int getVal(){
    return computVal;
}   

}

this is called as...

int hooray = (new Snippet()).getVal();
user462990
  • 5,472
  • 3
  • 33
  • 35