views:

118

answers:

3

I have a class (RestClient.java) that extends AsyncTask: package org.stocktwits.helper;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.AsyncTask;
import android.util.Log;

public class RestClient extends AsyncTask<String, Void, JSONObject>{
    public JSONObject jsonObj = null;
    private static String convertStreamToString(InputStream is) {
        /*
         * To convert the InputStream to String we use the BufferedReader.readLine()
         * method. We iterate until the BufferedReader return null which means
         * there's no more data to read. Each line will appended to a StringBuilder
         * and returned as String.
         */
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return sb.toString();
    }


    /* This is a test function which will connects to a given
     * rest service and prints it's response to Android Log with
     * labels "Praeda".
     */
    public static JSONObject connect(String url)
    {

        HttpClient httpclient = new DefaultHttpClient();


        // Prepare a request object
        HttpGet httpget = new HttpGet(url); 

        // Execute the request
        HttpResponse response;
        try {
            response = httpclient.execute(httpget);
            // Examine the response status
            Log.i("Praeda",response.getStatusLine().toString());

            // Get hold of the response entity
            HttpEntity entity = response.getEntity();

            if (entity != null) {

                // A Simple JSON Response Read
                InputStream instream = entity.getContent();
                String result= convertStreamToString(instream);

                // A Simple JSONObject Creation
                JSONObject json=new JSONObject(result);

                // Closing the input stream will trigger connection release
                instream.close();

                return json;
            }


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

        return null;
    }

    @Override
    protected JSONObject doInBackground(String... urls) {
        return connect(urls[0]);
    }

    @Override
    protected void onPostExecute(JSONObject json ) {
        this.jsonObj = json;
    }

    public void setJSONObject(JSONObject jsonFromUI){
        this.jsonObj = jsonFromUI;
    }

    public JSONObject getJSONObject(){
        return this.jsonObj;
    }

}

I am trying to execute the AsyncTask on my Main class (Main.java):

    RestClient rc = new RestClient();
    JSONObject json = new JSONObject();
    rc.setJSONObject(json);
    rc.execute(buildQuery());
    json = rc.getJSONObject();

//do some stuff with the json object
try { JSONObject query = json.getJSONObject("query");
//...
}

json is null because it is called before onPostExecute(). How can I get my JSON?

UPDATE: I need to run this try block in onPostExecute():

try {

            JSONObject query = json.getJSONObject("query");
            JSONObject results = query.getJSONObject("results");

            if (query.getString("count").equals("1")) { // YQL JSON doesn't
                // return an array for
                // single quotes
                JSONObject quote = results.getJSONObject("quote");

                Quote myQuote = new Quote();
                myQuote.setName(quote.getString("Name"));
                myQuote.setSymbol(quote.getString("Symbol"));
                myQuote.setLastTradePriceOnly(quote
                        .getString("LastTradePriceOnly"));
                myQuote.setChange(quote.getString("Change"));
                myQuote.setOpen(quote.getString("Open"));
                myQuote.setMarketCapitalization(quote
                        .getString("MarketCapitalization"));
                myQuote.setDaysHigh(quote.getString("DaysHigh"));
                myQuote.setYearHigh(quote.getString("YearHigh"));
                myQuote.setDaysLow(quote.getString("DaysLow"));
                myQuote.setYearLow(quote.getString("YearLow"));
                myQuote.setVolume(quote.getString("Volume"));
                myQuote.setAverageDailyVolume(quote
                        .getString("AverageDailyVolume"));
                myQuote.setPeRatio(quote.getString("PERatio"));
                myQuote.setDividendYield(quote.getString("DividendYield"));
                myQuote.setPercentChange(quote.getString("PercentChange"));

                quotesAdapter.add(myQuote);}
A: 

execute() always returns the AsyncTask itself. The object you return from doInBackground() is handed to you in onPostExecute().

Romain Guy
thanks for the clarification. How can I get the JSONObject from onPostExecute() ?
Sheehan Alam
+1  A: 

I'm be mistaken by result of doInBackground can be consumed in onPostExecute

doInBackground(Params...), invoked on the background thread immediately after on PreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.

@Override

protected void onPostExecute(JSONObject json ) {
// DO stuff here ( it's UI thread )
 mJsonFromTheActivity = json;
}
Alex Volovoy
so lets say onPostExecute() returns a JSONObject. How can I call this from my main class? Can I just say JSONObject json = rc.onPostExecute() and get the returned object?
Sheehan Alam
No, but you can assign that to member var from your onPostExecute
Alex Volovoy
This may not (and probably is not) the proper way, but one way I've done it is to declare a global variable, and then in the onPostExecute method, set that variable to the variable passed into onPostExecute. e.g. Private JSONObject jsonObject; ...onPostExecute(JSONObject json) { jsonObject = json; }. I would also like to know a better way, but I've not done too much searching on this yet.
kcoppock
Good example of it - is lazy thumb downloads right ? Let me find the url
Alex Volovoy
http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html
Alex Volovoy
If your json object is member variable in the same activity where your asynctask lives you assign it. If not you pass it by creating constructor to your async task. See the link, he's passing the view and caching it as weak reference
Alex Volovoy
@kcoppock so would you access the object like this? JSONObject json = rc.jsonObj; //assuming jsonObj is the member being set in onPostExecute?
Sheehan Alam
Define you mJson in the Activity where AsyncTask lives. The on post execute do mJson = json;
Alex Volovoy
@Alex I have updated my question to include my implementation of onPostExecute(). I also show how I am trying to access the member JSON. Can you tell me what I'm doing wrong? onPostExecute() gets called after I make the assignment, so it is always null...
Sheehan Alam
if mJsonFromTheActivity is in the UI thread (Main.java) how does RestClient.java (which implements onPostExecute()) have a reference to it?
Sheehan Alam
I didn't take a look at all you changes carefully enough , sorry . So onPostExecute - what's the value of json coming from doInBackground ?
Alex Volovoy
new RestClient (mJsonFromTheActivity).execute();
Alex Volovoy
I am setting my activity json obj via setJSONObject() and then calling execute(), however the JSON object is still null, even though in onPostExecute() the JSON has a valid value. I have updated my code in my question to reflect the changes.
Sheehan Alam
you setting your object to UI object first. Then you create NEW object JSONObject json=new JSONObject(result); and setting var object to it.
Alex Volovoy
What happens if you do what you were doing beforerc.execute(buildQuery());JSONObject json = rc.getJSONObject();
Alex Volovoy
it seems like onPostExecute() gets called after I do some work in my try{}...
Sheehan Alam
Well, of course - it's a background task !
Alex Volovoy
If you can - go ahead - i have no idea what work need to be done between try-catch
Alex Volovoy
I just posted my try block. I am basically parsing the JSON, building an object, and adding it to my ArrayAdapter. How do I move this into onPostExecute()?
Sheehan Alam
We probably can make it work, but for the time sake, move your task as nested class to activity and you'll have access to your adapter and whatever you else need from activity.
Alex Volovoy
@Alex - thank you for your diligent follow through. I have followed all of your advice, and async task is working properly :)
Sheehan Alam
A: 

If you have your asynctask as a nested inner class of your activity, you can set one of your activities variables to the result of your asynctask

Falmarri