0

I have an app I am building that uses an action bar search to send the search term to an online api which sends back json results.

So far I have search working, and coded the json parser to look at the results. I have not worked out displaying the results in a listview yet.

When I try searching with the api request and json parser I get a force close.

Log Cat:

06-04 20:23:15.542: D/libEGL(31832): loaded /vendor/lib/egl/libEGL_POWERVR_SGX540_120.so
06-04 20:23:15.558: D/libEGL(31832): loaded /vendor/lib/egl/libGLESv1_CM_POWERVR_SGX540_120.so
06-04 20:23:15.566: D/libEGL(31832): loaded /vendor/lib/egl/libGLESv2_POWERVR_SGX540_120.so
06-04 20:23:15.667: D/OpenGLRenderer(31832): Enabling debug mode 0
06-04 20:23:20.386: E/SpannableStringBuilder(31832): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
06-04 20:23:20.386: E/SpannableStringBuilder(31832): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
06-04 20:23:20.472: E/SpannableStringBuilder(31832): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
06-04 20:23:20.472: E/SpannableStringBuilder(31832): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
06-04 20:23:27.120: D/AndroidRuntime(31832): Shutting down VM
06-04 20:23:27.120: W/dalvikvm(31832): threadid=1: thread exiting with uncaught exception (group=0x4121c930)
06-04 20:23:27.144: E/AndroidRuntime(31832): FATAL EXCEPTION: main
06-04 20:23:27.144: E/AndroidRuntime(31832): android.os.NetworkOnMainThreadException
06-04 20:23:27.144: E/AndroidRuntime(31832):    at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1117)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at java.net.InetAddress.lookupHostByName(InetAddress.java:385)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at java.net.InetAddress.getAllByName(InetAddress.java:214)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:137)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at com.example.beerportfoliopro.JSONParser.getJSONFromUrl(JSONParser.java:38)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at com.example.beerportfoliopro.MainActivity.onQueryTextSubmit(MainActivity.java:53)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at android.widget.SearchView.onSubmitQuery(SearchView.java:1161)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at android.widget.SearchView.access$900(SearchView.java:92)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at android.widget.SearchView$8.onEditorAction(SearchView.java:1139)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at android.widget.TextView.onEditorAction(TextView.java:4117)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at com.android.internal.widget.EditableInputConnection.performEditorAction(EditableInputConnection.java:138)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at com.android.internal.view.IInputConnectionWrapper.executeMessage(IInputConnectionWrapper.java:297)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at com.android.internal.view.IInputConnectionWrapper$MyHandler.handleMessage(IInputConnectionWrapper.java:77)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at android.os.Handler.dispatchMessage(Handler.java:99)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at android.os.Looper.loop(Looper.java:137)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at android.app.ActivityThread.main(ActivityThread.java:5226)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at java.lang.reflect.Method.invokeNative(Native Method)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at java.lang.reflect.Method.invoke(Method.java:511)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
06-04 20:23:27.144: E/AndroidRuntime(31832):    at dalvik.system.NativeStart.main(Native Method)

API request and JSON parsing

url = url + query;
            Toast.makeText(this, url, Toast.LENGTH_SHORT).show();

            // Creating JSON Parser instance
            JSONParser jParser = new JSONParser();

            // getting JSON string from URL
            JSONObject json = jParser.getJSONFromUrl(url);

            // Getting Array of beers
            try {
                JSONArray beers = json.getJSONArray("data");

                // looping through All beers
                for(int i = 0; i < beers.length(); i++){
                    JSONObject c = beers.getJSONObject(i);

                    //get beer information
                    String beerID = c.getString("id");
                    String beerName = c.getString("name");
                    String beerDescription = c.getString("description");
                    String beerABV = c.getString("abv");
                    String beerIBU = c.getString("ibu");


                }


            } 

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

JSONParser.java

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

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

import android.util.Log;

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;

    }
}
Mike
  • 6,751
  • 23
  • 75
  • 132

3 Answers3

2

You should just check printStack

android.os.NetworkOnMainThreadException

Is your problem, from the name of Exception it seams obvious, you should not make network request from UI Thread.

Have a look at AsyncTask in android documentation.

Happy Dev
  • 573
  • 10
  • 17
  • hmmm I am following this tutorial here and it seems they were able to make it work: http://www.androidhive.info/2012/01/android-json-parsing-tutorial/ – Mike Jun 05 '13 at 00:43
  • I suspect the prohibition on making network accesses from the UI thread may be relatively new. If the tutorial was written when an older version of Android was in use, it might have worked (but been bad practice), but doesn't work any more. – Edward Falk Jun 05 '13 at 00:58
2

Execute the code that makes the request at least on another thread. Easiest way is to use the AsyncTask.

    final String jsonUrl = url + query;
    Toast.makeText(this, jsonUrl, Toast.LENGTH_SHORT).show();

    new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... voids) {
            // Creating JSON Parser instance
            JSONParser jParser = new JSONParser();

            // getting JSON string from URL
            JSONObject json = jParser.getJSONFromUrl(url);

            // Getting Array of beers
            try {
                JSONArray beers = json.getJSONArray("data");

                // looping through All beers
                for(int i = 0; i < beers.length(); i++){
                    JSONObject c = beers.getJSONObject(i);

                    //get beer information
                    String beerID = c.getString("id");
                    String beerName = c.getString("name");
                    String beerDescription = c.getString("description");
                    String beerABV = c.getString("abv");
                    String beerIBU = c.getString("ibu");


                }


            }

            catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }.execute();
lukasz
  • 3,121
  • 1
  • 21
  • 20
  • what is the final thing you added in front of url? – Mike Jun 05 '13 at 00:56
  • 1
    You need to make a local variable final to access it from an anonymous class. You don't need this if your `url` is a member of your class. – lukasz Jun 05 '13 at 01:02
  • thanks, this fixes the force close, but I tried to put a toast in it to see if I am getting anything for the beer names from the api and it wouldnt allow me to put a toast in the anonymous class – Mike Jun 05 '13 at 01:06
  • You can, but `this` referes to the actual anonymous class which is not a context. You need to access to the activity, which is the parent instance : `Toast.makeText(YouActivity.this, "foo", Toast.LENGTH_SHORT).show();` – lukasz Jun 05 '13 at 01:10
  • I tried: Toast.makeText(MainActivity.this, "foo", Toast.LENGTH_SHORT).show(); and I do not get an error but the toast does not show up – Mike Jun 05 '13 at 01:19
  • Are you executing the async task ? `new AsyncTask<>(){...}.execute();` – lukasz Jun 05 '13 at 01:22
  • yes, http://pastebin.com/TFzgGpii – Mike Jun 05 '13 at 01:25
  • It should work, you must not enter in the loop. Use debugger or Log.d("TAG", "") to check if the json is properly parsed upstream the loop. – lukasz Jun 05 '13 at 01:30
0

Looks like a StrictMode exception. You're not supposed to do any kind of network operation on the UI thread (which any operation is from the activity context unless explicitly put onto another thread) so you'd want to use one of the Android-y ways of doing things like this, AsyncTask.

http://developer.android.com/training/articles/perf-anr.html

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