0

As mentioned I get the above error which I know is because my application is doing networking in UI thread. I went through a lot of stackoverflow questions which advise to use AsyncTask for this purpose. From what I understand asynctask is asynchronous and will run independently in the background. But I need to fetch the data from http and display on the main thread. So basically my UI thread should be blocked till I have the JSON fetched so that I can display it.

My questions are 1) Since I need to run http networking in another thread how do I do it? 2) Do I use an async thread? 3) How do I block my UI thread for the async thread to fetch the result? 4) How do I pass the result from async thread back to UI thread?

This is the current JSON parser class that I use.

public class JSONParser {

static InputStream is = null;
static JSONObject jObj = null;
static String json = "";

// constructor
public JSONParser() {

}

public JSONArray getJSONfromURL(String url) {
    // initialize
    InputStream is = null;
    String result = "";
    JSONArray jArray = null;
    // http post
    try {
        HttpClient httpclient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(url);
        HttpResponse response = httpclient.execute(httpGet);
        HttpEntity entity = response.getEntity();
        is = entity.getContent();

    } catch (Exception e) {
        Log.e("log_tag", "Error in http connection " + e.toString());
        return null;
    }

    // convert response to string
    try{
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                is, "iso-8859-1"), 8);
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            sb.append(line + "\n");
        }
        is.close();
        result = sb.toString();
        Log.e("log_tag", "JSON data" + result);
    } catch (Exception e) {
        Log.e("log_tag", "Error converting result " + e.toString());
        return null;
    }

    // try parse the string to a JSON object
    try {           
        jArray = new JSONArray(result);
    } catch (JSONException e) {
        Log.e("log_tag", "Error parsing data " + e.toString());
        return null;
    }

    return jArray;
}

}

And this is my MainActivity where I call JSONparser to fetch some data that I need to display

    JSONArray json = jParser.getJSONfromURL(temp);

    if (json == null) {
        return -1;
    }

    for (int i = 0; i < json.length(); i++) {
        try {
            JSONObject c = json.getJSONObject(i);
            // Getting Array of Contacts
            // Storing each json item in variable
            asr_iq = c.getString("lMAsr");
            sunrise_iq = c.getString("lMSunrise");
            fajr_iq = c.getString("lMFajr");
            isha_iq = c.getString("lMIsha");
            dhuhr_iq = c.getString("lMDhuhr");
            maghrib_iq = c.getString("lMMaghrib");


        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
fzansari
  • 131
  • 1
  • 3
  • 12
  • I answered a similar question not so long ago. Take a look here http://stackoverflow.com/questions/16194355/jsonarray-in-a-listview-with-android – Sergey Benner Apr 30 '13 at 22:02
  • Thanks Sergey. I liked your answer. But I got it to work using an Async thread – fzansari May 02 '13 at 19:12

2 Answers2

1

Load your asynctask on the UI thread.

If you cannot do any network related operation on the UI Thread Honeycomb and later. You will get a NetworkOnMainThread Exception.

    new MyTask(url).execute();// can pass parameter to class constructor 
    // can also pass url to doInBackground.   

Async task

 class MyTask extends AsyncTask<Void,Void,Void>
 {
    String url;   

    public MyTask(String url)
    {
         this.url =url
    }      
@Override
protected Void doInBackground(Void... params) {
    // all your network related operation
            // invoked on the background thread
            // all code from getJSONfromURL(param)     
            // do not update ui here   
    return null;
}

@Override
protected void onPostExecute(Void result) { // invoked on the ui thread
    // TODO Auto-generated method stub
    super.onPostExecute(result);
            // dismiss progress dialog
            // update ui here
}

@Override
protected void onPreExecute() {
    // TODO Auto-generated method stub
    super.onPreExecute();
            // display progress dialog  
}

@Override
protected void onProgressUpdate(Void... values) {
    // TODO Auto-generated method stub
    super.onProgressUpdate(values);
}

}

Detailed information @ http://developer.android.com/reference/android/os/AsyncTask.html

Edit:

Use a Handler. Return result in doInBaCkground().

Example in onPostExecute()

 Message msg=new Message();
 msg.obj=result.getProperty(0).toString();
 mHandler.sendMessage(msg);

In your activity onCreate()

 Handler mHandler = new Handler() { 
   @Override public void handleMessage(Message msg) { 
      //ArrayList s=(ArrayList)msg.obj;
      SoapObject s =(SoapObject) msg.obj;
      tv.setText("Result = "+s.toString());

   }
};

You can also use runonuithread to update ui from doInBackGround()

     runOnUiThread(new Runnable() //run on ui thread
                 {
                  public void run() 
                  { 

                      _tv.setText("update from doinbackground");

                 }
                 });
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • How does this ensure my UI thread is blocked till I get JSON data? I understand that I can display my UI data in onPostExecute(). But is there a way to pass the JSONarray/result back to the UI thread's calling function? I would like to do all my display in the calling function where I have a bunch of other stuff to display. – fzansari Apr 30 '13 at 23:20
  • My bad. Just figured after reading that onPostExecute() is called after doInBackground() finishes. So the serialization is taken care of. But still if you can answer the second part of my question that would be great. "Is there a way to pass the JSONarray/result back to the UI thread's calling function? I would like to do all my display in the calling function where I have a bunch of other stuff to display." – fzansari Apr 30 '13 at 23:51
  • @user2040855 you can use a handler for this purpose – Raghunandan May 01 '13 at 05:20
0

Using Core Java,

  1. Have your getJson execution logic in a Runnable/Callable(Java concurrency class), submit it via executors so that its an Asynch call.

  2. Then with in your Runnable/Callable once json is retrived call the class which will have logic to display the json, this clas can be designed as a listener and you may publish an even after getting json response

bhwp
  • 41
  • 3
  • If I knew Java multithreading , I wouldnt have asked this question. I have a Linux/C background and runnable, callable, concurrency class is going over my head. If you can give some useful code to do that, it would be helpful. – fzansari Apr 30 '13 at 23:13