8

How do I get the data from my AsyncTask? My MainActivity is calling the DataCall.getJSON function that triggers the AsyncTask but I am not sure how to get the data back to the original Activity.

MainActivity with call to DataCall that should return a string and save it in state_data

String state_data =  DataCall.getJSON(spinnerURL,spinnerContentType); 

DataCall:

public class DataCall extends Activity {
    private static final String TAG = "MyApp";


    private class DownloadWebPageTask extends AsyncTask<String, Void, String> {


        protected String doInBackground(String... urls) {
            String response = "";
            for (String url : urls) {
                DefaultHttpClient client = new DefaultHttpClient();
                HttpGet httpGet = new HttpGet(url);
                try {
                    HttpResponse execute = client.execute(httpGet);
                    InputStream content = execute.getEntity().getContent();

                    BufferedReader buffer = new BufferedReader(
                            new InputStreamReader(content));
                    String s = "";
                    while ((s = buffer.readLine()) != null) {
                        response += s;
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return response;
        }


        protected void onPostExecute(String result) {
            //THIS IS WHERE I NEED TO RETURN MY DATA TO THE MAIN ACTIVITY. (I am guessing)
        }

        }

    public void getJSON(String myUrlString, String contentType) {
        DownloadWebPageTask task = new DownloadWebPageTask();
        task.execute(new String[] { "http://www.mywebsite.com/" + myUrlString });

    }

}
Denoteone
  • 4,043
  • 21
  • 96
  • 150
  • 1
    why don't you try a Service driven REST call model? instead of doing the request on a Activity dependant thread? – Necronet Oct 02 '11 at 09:08

6 Answers6

24

modify your AsyncTask as below:

public class GetData extends AsyncTask<String, Void, String>
{
    DataDownloadListener dataDownloadListener;
    public GetData()
    {
        //Constructor may be parametric 
    }
    public void setDataDownloadListener(DataDownloadListener dataDownloadListener) {
        this.dataDownloadListener = dataDownloadListener;
    }
    @Override
    protected Object doInBackground(Object... param) 
    {
        // do your task...
        return null;
    }
    @Override
    protected void onPostExecute(Object results)
    {       
        if(results != null)
        {               
        dataDownloadListener.dataDownloadedSuccessfully(results);
        }
        else
        dataDownloadListener.dataDownloadFailed();
    }
    public static interface DataDownloadListener {
        void dataDownloadedSuccessfully(Object data);
        void dataDownloadFailed();
    }
}

and use it in your Activity

GetData getdata = new GetData();
getdata.setDataDownloadListener(new DataDownloadListener()
{
    @SuppressWarnings("unchecked")
    @Override
    public void dataDownloadedSuccessfully(Object data) {
    // handler result
    }
    @Override
    public void dataDownloadFailed() {
    // handler failure (e.g network not available etc.)
    }
});
getdata.execute("");

NOTE: For the people who are reading this.

Please consider this post for the best and perhaps right implementation.

Community
  • 1
  • 1
Adil Soomro
  • 37,609
  • 9
  • 103
  • 153
  • But how would I pass my variables to the GetData Class? Thanks for the help. +1 – Denoteone Oct 02 '11 at 04:14
  • Well for this, as I have mentioned you can pass variables through the constructor of `GetData` and make them field of `GetData` class for further use of them in methods. – Adil Soomro Oct 02 '11 at 10:50
  • Hi Adil, Which Thread will handle will handle the dataDownloadedSuccessfully() ? Will it be the AsyncTask thread or UI thread? I would like the UI thread to handle my result so that i can update the UI. Any insights on this? – Akh Mar 01 '12 at 19:07
  • 1
    Hay @AKh `onPostExecute()` is called on UI thread, so if you put `dataDownloadedSuccessfully()` inside `onPostExecute()`, it will be called on UI thread and you can perform updates to UI. – Adil Soomro Mar 02 '12 at 05:09
  • How come your AsyncTask is set to return a String type, but `doInBackground` is set to return an Object but actually returns null? Is it just me or is that really wrong? – Jake Wilson Mar 29 '12 at 01:29
  • that is just an example. You can return your own object there. see I've placed check in `onPostExecute()` about result is `null` or not. – Adil Soomro Mar 29 '12 at 04:58
  • The onPostExecute() method itself is already a onEventCallback() method and the only purpose is to process result returned by background thread. What is the point of doing nothing here but tie another dummy listener within onPostExecute() method, pass the result, then process the result in this second level listenerCallback method. It doesn't make any sense to me. – yorkw Apr 04 '12 at 09:15
  • @yorkw: Yep. you are right. But this scenario helps in the case if you have separate class of AsyncTask (i.e not in Activity class) and you want to use it more than one Activities. – Adil Soomro Apr 04 '12 at 09:49
  • @AdilSoomro, This is another thing I would against. Java inner class syntax has it own reason to exist. When talking about code refactoring from OOP perspective, think more from problem abstraction level, instead of simply strip inner class off at code level. I've answered a similar question explains this problem before at [here](http://stackoverflow.com/questions/8295003/best-way-to-manage-the-progressdialog-from-asynctask/8317071#8317071). – yorkw Apr 04 '12 at 10:06
  • Brilliant implementation!! – Daniel Aug 10 '14 at 13:44
7

The key for me was to create a class called URLWithParams or something because AsyncTask will allow only 1 type to be sent IN, and I needed both the URL and the params for the HTTP request.

public class URLWithParams {

    public String url;
    public List<NameValuePair> nameValuePairs;

    public URLWithParams()
    {
        nameValuePairs = new ArrayList<NameValuePair>();
    }
}

and then I send it to a JSONClient:

public class JSONClient extends AsyncTask<URLWithParams, Void, String> {
    private final static String TAG = "JSONClient";

    ProgressDialog progressDialog ;
    GetJSONListener getJSONListener;
    public JSONClient(GetJSONListener listener){
        this.getJSONListener = listener;
    }

    @Override
    protected String doInBackground(URLWithParams... urls) {
        return connect(urls[0].url, urls[0].nameValuePairs);
    }

    public static String connect(String url, List<NameValuePair> pairs)
    {
        HttpClient httpclient = new DefaultHttpClient();

        if(url == null)
        {
            Log.d(TAG, "want to connect, but url is null");
        }
        else
        {
            Log.d(TAG, "starting connect with url " + url);
        }

        if(pairs == null)
        {
            Log.d(TAG, "want to connect, though pairs is null");
        }
        else
        {
            Log.d(TAG, "starting connect with this many pairs: " + pairs.size());
            for(NameValuePair dog : pairs)
            {
                Log.d(TAG, "example: " + dog.toString());
            }
        }

        // Execute the request
        HttpResponse response;
        try {
            // Prepare a request object
            HttpPost httpPost = new HttpPost(url); 
            httpPost.setEntity(new UrlEncodedFormEntity(pairs));
            response = httpclient.execute(httpPost);
            // Examine the response status
            Log.i(TAG,response.getStatusLine().toString());

            BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
            String json = reader.readLine();
            return json;

        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return null;
    }



    @Override
    protected void onPostExecute(String json ) {
        getJSONListener.onRemoteCallComplete(json);
    }


    public interface GetJSONListener {
        public void onRemoteCallComplete(String jsonFromNet);
    }

}

Then call it from my main class like this

public class BookCatalog implements GetJSONListener {
    private final String TAG = this.getClass().getSimpleName();

    private String catalog_url = "URL";

    private void getCatalogFromServer() {

        URLWithParams mURLWithParams = new URLWithParams();
        mURLWithParams.url = catalog_url;

        try {
            JSONClient asyncPoster = new JSONClient(this);
            asyncPoster.execute(mURLWithParams);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void onRemoteCallComplete(String jsonBookCatalogList) {

        Log.d(TAG, "received json catalog:");
        Log.d(TAG, jsonBookCatalogList);
    JSONObject bookCatalogResult;
    try {
        bookCatalogResult = (JSONObject) new JSONTokener(jsonBookCatalogList).nextValue();
        JSONArray books = bookCatalogResult.getJSONArray("books");

        if(books != null) {
            ArrayList<String> newBookOrdering = new ArrayList<String>();
            int num_books = books.length();
            BookCatalogEntry temp;

            DebugLog.d(TAG, "apparently we found " + Integer.toString(num_books) + " books.");
            for(int book_id = 0; book_id < num_books; book_id++) {
                JSONObject book = books.getJSONObject(book_id);
                String title = book.getString("title");
                int version = book.getInt("price");
            }
        }

    } catch (JSONException e) {
        e.printStackTrace();
    } 

    }


}
Thunder Rabbit
  • 5,405
  • 8
  • 44
  • 82
1

Serialize it and then read it. The only way I'm aware of.

Ron
  • 24,175
  • 8
  • 56
  • 97
asenovm
  • 6,397
  • 2
  • 41
  • 52
1

Although i disagree creating a new activity for that simple task there is

startActivityForResult()

to get data from another activity.

Check this. You can store your data to the Intent's extras. But still if you have a large amount of data you better off write it to a file get the result from the other activity that is done downloading and then read the file.

weakwire
  • 9,284
  • 8
  • 53
  • 78
1

Some options:

a) Make your bean implement Serializable interface, you can then pass your bean through Intent.

b) Implement Application interface (you need to make an entry in manifest), Have setter\getter method in your Application class. You can set your bean in Application from AsyncTask and later retrieve from Activity.

Ron
  • 24,175
  • 8
  • 56
  • 97
Siddhartha
  • 158
  • 5
0

Sorry for answering so late, i think by this time you might have solved this problem. when i was searching for something else, i came across your question. I'm pasting a link here which might of some help for others.

Community
  • 1
  • 1
Jayanth N
  • 25
  • 1
  • 7