0

I am trying to run an app based on WorlBank API. I have a JSON URL to get data about a country and then show it in TextViews. Simple. But as soon as I run the app in closes.

Here are my files:

Main Activity:

public class MainActivity extends Activity {

//URL to get JSON Array
private static String url = "http://api.worldbank.org/countries/ir?format=json";

//JSON node Names
private static final String PAGE = "page";
private static final String VALUE = "value";
private static final String NAME = "name";
private static final String GEO = "region";

JSONArray page = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //Creating new JSON Parser
    JSONParser jParser = new JSONParser();
    // Getting JSON from URL
    JSONObject json = jParser.getJSONFromUrl(url);

    try{
        //Getting JSON Array
        page = json.getJSONArray(PAGE);
        JSONObject c = page.getJSONObject(0);

        //Sorting JSON item in a Variable
        String value = c.getString(VALUE);
        String name = c.getString(NAME);
        String geo = c.getString(GEO);

        //Importing to TextView
        final TextView id1 = (TextView) findViewById(R.id.id);
        final TextView name1 = (TextView) findViewById(R.id.name);
        final TextView geo1 = (TextView) findViewById(R.id.geo);

        //set JSON Data in TextView
        id1.setText(value);
        name1.setText(name);
        geo1.setText(geo);
    } catch (JSONException e){
        e.printStackTrace();
    }



}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

    }

JSONParser:

public class JSONParser {
static InputStream is = null;
static JSONObject jObj = null;
static String json = "";

// constructor
public JSONParser() {

}

public JSONObject getJSONFromUrl(String url) {

    // Making HTTP request
    try {
        // defaultHttpClient
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);

        HttpResponse httpResponse = httpClient.execute(httpPost);
        HttpEntity httpEntity = httpResponse.getEntity();
        is = httpEntity.getContent();           

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    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();
        json = sb.toString();
    } catch (Exception e) {
        Log.e("Buffer Error", "Error converting result " + e.toString());
    }

    // try parse the string to a JSON object
    try {
        jObj = new JSONObject(json);
    } catch (JSONException e) {
        Log.e("JSON Parser", "Error parsing data " + e.toString());
    }

    // return JSON String
    return jObj;

}
}

XML:

<TextView
    android:id="@+id/id"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/name"
    android:textAppearance="?android:attr/textAppearanceLarge" />

<TextView
    android:id="@+id/name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/id"
    android:textAppearance="?android:attr/textAppearanceLarge" />

<TextView
    android:id="@+id/geo"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/id"
    android:layout_alignParentTop="true"
    android:layout_marginTop="76dp"
    android:textAppearance="?android:attr/textAppearanceLarge" />

Any idea?

world bank api: http://data.worldbank.org/node/18

UPDATE:

android:minSdkVersion="8"

android:targetSdkVersion="18"

FATAL EXCEPTION: main
E/AndroidRuntime(966): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.jsonsyctask/com.example.jsonsyctask.Main}: android.os.NetworkOnMainThreadException
E/AndroidRuntime(966):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
E/AndroidRuntime(966):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
E/AndroidRuntime(966):  at android.app.ActivityThread.access$600(ActivityThread.java:141)
E/AndroidRuntime(966):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
E/AndroidRuntime(966):  at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(966):  at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime(966):  at android.app.ActivityThread.main(ActivityThread.java:5103)
E/AndroidRuntime(966):  at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(966):  at java.lang.reflect.Method.invoke(Method.java:525)
E/AndroidRuntime(966):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
10
  • try to run in async task... Commented Nov 22, 2013 at 2:58
  • @HarshitRathi I dont know about this. Can you explain more please? Commented Nov 22, 2013 at 3:01
  • 1
    use this link androidhive.info/2012/01/android-json-parsing-tutorial it will make help you to find out how to parse json in async task... Commented Nov 22, 2013 at 3:03
  • 1
    Firstly don't just make statements like "But as soon as I run the app in closes." without providing stacktraces from logcat - show us errors as well as code. Secondly, the answer to your question is either, as others have said, you're doing network operations on the UI thread (OK on older versions of Android but not later ones) OR (and this will bite you anyway) that URL returns a JSON array and not a JSON object. Also you are doing an HTTP Post whereas an HTTP GET should be used. Fix all those and you're good to go. Commented Nov 22, 2013 at 3:14
  • I agree with @Squonk. You should post your log. There many problems with the above code as mentioned.. Commented Nov 22, 2013 at 3:16

5 Answers 5

5

The problem is happening because you are trying to perform network operations on the UI thread. You need to use a background thread for network operations.

Use an AsyncTask as follows:

public class MainActivity extends Activity {

    //URL to get JSON Array
    private static String url = "http://api.worldbank.org/countries/ir?format=json";

    //JSON node Names
    private static final String PAGE = "page";
    private static final String VALUE = "value";
    private static final String NAME = "name";
    private static final String GEO = "region";

    JSONArray page = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new GetJSONTask().execute(url);

        // do not parse here..
        ...
        ...
    }
    ...
    ...

    class GetJSONTask extends AsyncTask<String, Void, JSONObject> {


        protected JSONObject doInBackground(String... urls) {
            try {
                JSONParser jParser = new JSONParser();
                return jParser.getJSONFromUrl(urls[0]);
            } catch (Exception e) {
                return null;
            }
        }

        protected void onPostExecute(JSONObject json) {
            // do all the parsing here:
            try {
                //Getting JSON Array
                page = json.getJSONArray(PAGE);
                JSONObject c = page.getJSONObject(0);

                //Sorting JSON item in a Variable
                String value = c.getString(VALUE);
                String name = c.getString(NAME);
                String geo = c.getString(GEO);

                //Importing to TextView
                final TextView id1 = (TextView) findViewById(R.id.id);
                final TextView name1 = (TextView) findViewById(R.id.name);
                final TextView geo1 = (TextView) findViewById(R.id.geo);

                //set JSON Data in TextView
                id1.setText(value);
                name1.setText(name);
                geo1.setText(geo);
            }
            catch (JSONException e)
            {
                e.printStackTrace();
            }
        } 
    }
}

Ref: http://developer.android.com/reference/android/os/AsyncTask.html

update another bug spotted, update XML

<TextView
    android:id="@+id/id"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/name"
    android:textAppearance="?android:attr/textAppearanceLarge" />

<TextView
    android:id="@+id/name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textAppearance="?android:attr/textAppearanceLarge" />
...
...

You cannot have two views and say A below B, then B below A that will cause problems!

Sign up to request clarification or add additional context in comments.

6 Comments

That's not a guaranteed answer to the question (depending on Android version, networking on the UI thread is allowed and the OP doesn't tell us which version he is using). It may well be correct at this stage but see my comment on the OP's question - he has a few other problems to fix.
As mentioned, I agree with you. Will update my answer based on further information when provided..
@Squonk I just updated my post and added first few lines of the logcat.
@user2977338 you are getting NetworkOnMainThread exception. This is the what I have explained above. Please follow my answer and report if there are any further crashes..
Thanks for your post. Just tried. app stopped and this is the catlog: E/AndroidRuntime(1136): FATAL EXCEPTION: main E/AndroidRuntime(1136): java.lang.IllegalStateException: Circular dependencies cannot exist in RelativeLayout E/AndroidRuntime(1136): at android.widget.RelativeLayout$DependencyGraph.getSortedViews(RelativeLayout.java:1692) E/AndroidRuntime(1136): at android.widget.RelativeLayout.sortChildren(RelativeLayout.java:382)
|
1

You can greatly simplify everything you are doing using my droidQuery library:

$.ajax(new AjaxOptions().url(url).success(new Function() {
    @Override
    public void invoke($ d, Object... args) {
        JSONObject json = (JSONObject) args[0];
        JSONArray page = json.getJSONArray(PAGE);
        JSONObject c = page.getJSONObject(0);

        $.with(MyActivity.this, R.id.id).text(c.getString(VALUE))
                            .id(R.id.name).text(c.getString(NAME))
                            .id(geo).text(c.getString(GEO));

    }
}));

2 Comments

Umm... why the down vote? This simplifies the OP's code significantly, and handles all background thread stuff using AsyncTasks.
I downvoted because instead of trying to solve the OP's immediate problem you posted code using a totally different technology. You simply made the assumption they would automatically switch their approach to coding. Bearing in mind the OP is struggling to perform what is a basic GET request to retrieve a JSON string (using POST instead) and was trying to process the resultant JSON array as a JSON object, I didn't feel it appropriate that you'd assumed they would understand your approach or know how to use it.
0

I used Kevin Sawicki's HTTP Request Library which is very helpful, find the working example bellow. Don't forget to add android permission

<uses-permission android:name="android.permission.INTERNET" />

Retrieved json value from http://api.worldbank.org/countries/ir?format=json

JSON Values

package com.javasrilankansupport.testhttps;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.github.kevinsawicki.http.HttpRequest;
import com.github.kevinsawicki.http.HttpRequest.HttpRequestException;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    new DownloadTask().execute("http://api.worldbank.org/countries/ir?format=json");
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

private class DownloadTask extends AsyncTask<String, Long, Boolean> {
    protected Boolean doInBackground(String... urls) {
        try {

            // kevinsawicki's HttpRequest from github
            HttpRequest request = HttpRequest.get(urls[0])
                    .trustAllCerts() // for HTTPS request
                    .trustAllHosts() // to trust all hosts 
                    .acceptJson();   // to accept JSON objects 

            if (request.ok()) {

                JSONObject jsonObject;
                try {
                    String s = request.body();
                    Log.d("MyApp",
                            "Downloaded json data: "+ s);

                    //  change parameters according to your JSON 
                    jsonObject = new JSONObject(s);

                    JSONArray jsonArray = jsonObject
                            .getJSONArray("categories");

                    for (int i = 0; i < jsonArray.length(); i++) {
                        JSONObject jsonObj = jsonArray.getJSONObject(i);
                        Log.d("MyApp",
                                "Downloaded json data: "
                                        + jsonObj.getString("id") + "  "
                                        + jsonObj.getString("slug"));
                    }

                } catch (JSONException e) {
                    e.printStackTrace();
                }
            } else {
                System.out.print("error");
            }
        } catch (HttpRequestException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    protected void onProgressUpdate(Long... progress) {
        // progress bar here
    }

    @Override
    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
    }

 }
}

Comments

0

Getting data from server require following steps :

  1. make sure your generated json string is in correct format.You can find it on various site.
  2. while requesting from server you must use AsyncTask.

Following example can be helpful to understand the logic

package com.example.sonasys.net;
import java.util.ArrayList;
import java.util.HashMap;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.example.sonaprintersd.R;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import android.widget.TextView;

public class SingleContactActivity extends Activity {


private static final String TAG_CONTACTS = "Contacts";
private static final String TAG_POSTLINE = "PostLine";
private static final String TAG_Post_Img = "Post_Img";
private static final String TAG_Post_Img_O = "Post_Img_O";

private static String url;
TextView uid, pid;
JSONArray contacts = null;
private ProgressDialog pDialog;
String details;
// String imagepath = "http://test2.sonasys.net/Content/WallPost/b3.jpg";
String imagepath = "";
Bitmap bitmap;
ImageView image;
String imagepath2;

ArrayList<HashMap<String, String>> contactList;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_single_contact);

    url = "http://test2.sonasys.net/MobileApp/GetSinglePost?UserId="
            + uid.getText() + "&Post_ID=" + pid.getText();

    contactList = new ArrayList<HashMap<String, String>>();
    new GetContacts().execute();

}

private class GetContacts extends AsyncTask<Void, Void, Void> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // Showing progress dialog
        pDialog = new ProgressDialog(SingleContactActivity.this);
        pDialog.setMessage("Please wait...");
        pDialog.setCancelable(false);
        // pDialog.setTitle("Post Details");
        pDialog.show();

    }

    @Override
    protected Void doInBackground(Void... arg0) {
        // Creating service handler class instance
        ServiceHandler sh = new ServiceHandler();

        // Making a request to url and getting response
        String jsonStr = sh.makeServiceCall(url, ServiceHandler.GET);

        Log.d("Response: ", "> " + jsonStr);

        if (jsonStr != null) {
            try {
                JSONObject jsonObj = new JSONObject(jsonStr);

                // Getting JSON Array node
                contacts = jsonObj.getJSONArray(TAG_CONTACTS);

                // looping through All Contacts

                JSONObject c = contacts.getJSONObject(0);

                details = c.getString(TAG_POSTLINE);
                imagepath = c.getString(TAG_Post_Img);
                imagepath2 = c.getString(TAG_Post_Img_O);

            } catch (JSONException e) {
                e.printStackTrace();
            }
        } else {
            Log.e("ServiceHandler", "Couldn't get any data from the url");
        }

        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);
        // Dismiss the progress dialog
        if (pDialog.isShowing())
            pDialog.dismiss();
        /**/
        TextView Details = (TextView) findViewById(R.id.details);
        // Details.setText(details);
        Details.setText(android.text.Html.fromHtml(details));

    }
}





public class ServiceHandler {

static String response = null;
public final static int GET = 1;
public final static int POST = 2;

public ServiceHandler() {

}

/*
 * Making service call
 * @url - url to make request
 * @method - http request method
 * */
public String makeServiceCall(String url, int method) {



    return this.makeServiceCall(url, method, null);
}

/*
 * Making service call
 * @url - url to make request
 * @method - http request method
 * @params - http request params
 * 

 * */

public String makeServiceCall(String url, int method,List<NameValuePair> params) {

    try {
        // http client

        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpEntity httpEntity = null;
        HttpResponse httpResponse = null;

        // Checking http request method type
        if (method == POST) {
            HttpPost httpPost = new HttpPost(url);
            // adding post params
            if (params != null) {               
                httpPost.setEntity(new UrlEncodedFormEntity(params));

            }

            httpResponse = httpClient.execute(httpPost);

        } else if (method == GET) {
            // appending params to url
            if (params != null) {
                String paramString = URLEncodedUtils.format(params, "utf-8");
                url += "?" + paramString;
            }
            HttpGet httpGet = new HttpGet(url);

            httpResponse = httpClient.execute(httpGet);

        }
        httpEntity = httpResponse.getEntity();
        response = EntityUtils.toString(httpEntity);

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return response;

}

2 Comments

@benka can you suggest me how to format my post in a good way?
I would suggest to check this link: stackoverflow.com/editing-help, discussing formatting / markdown. Also when you write / edit a post there is help on the right and there is a big orange questionmark on the top right of your editor window which provides useful help if you click on it:) Moreover it doesn't get you any negative points or anything when someone edits your post, infact a well formatted post can help you gain more reputation.
-2

My guess is that this is because you're attempting network activity on the main thread. That's a no-no.

Perhaps adding a default exception handler and a breakpoint there will help-

Thread.setDefaultUncaughtExceptionHandler( new Thread.UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        throwable.printStackTrace();
    }
});

3 Comments

Thanks. Where should I add it in?
Adding a exception handler won't help, he simply needs to do the network stuff in a AsyncTask as already mentioned in the comments to his question.
I only meant that if he/she had a handler installed, they would be able to confirm that it is the issue- not that it would solve their problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.