user2977338
user2977338

Reputation: 135

Why my android app cannot get data from JSON url?

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)

Upvotes: 0

Views: 11312

Answers (5)

Phil
Phil

Reputation: 36289

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));

    }
}));

Upvotes: 1

user4213851
user4213851

Reputation:

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;

}

Upvotes: 0

Amulya Khare
Amulya Khare

Reputation: 7698

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!

Upvotes: 5

Chathura Wijesinghe
Chathura Wijesinghe

Reputation: 3349

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);
    }

 }
}

Upvotes: 0

Brad
Brad

Reputation: 486

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();
    }
});

Upvotes: -2

Related Questions