0

I'm writing my first Android app, and trying to get the hang of making a REST call from within the app. Following a couple pages and other SO posts, I've got this:

URL serverUrl = new URL("http://localhost:13980/api/maps/"); //the value is hardcoded for testing purposes

public String getMapsJson()
{
    Log.d("Minimap", ">> getting maps json from " + serverUrl.toString());
    String output = "";

    HttpURLConnection connection = null;

    try
    {
        connection = (HttpURLConnection) serverUrl.openConnection();
        connection.setRequestMethod("GET");
        Log.d("Minimap", "connection opened!");
        InputStream in = new BufferedInputStream(connection.getInputStream());
        Log.d("Minimap", "input stream captured");
        output = readStream(in);
        Log.d("Minimap", "stream read");
    }

    catch (Exception e)
    {
        Log.d("Minimap", e.getMessage()); //************* This is line 53 <<<<<<
    }

    finally
    {
        connection.disconnect();
    }


    Log.d("Minimap", "JSON: " + output);
    return output;
}

private String readStream(InputStream in)
{
    try
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        String line = reader.readLine();
        String output = line;

        while((line = reader.readLine()) != null)
            output += line;

        return output;
    }
    catch (IOException e)
    {
        e.printStackTrace();
        return "";
    }
}

The output I'm getting from logcat is just

11-19 07:38:31.599    3813-3813/com.northstar.minimap D/Minimap﹕ >> getting maps json from http://localhost:13980/api/maps/
11-19 07:38:31.599    3813-3813/com.northstar.minimap D/Minimap﹕ connection opened!

and then the app crashes with the following stack trace:

11-19 08:02:50.903      744-744/com.northstar.minimap E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.northstar.minimap/com.northstar.minimap.MapActivity}: java.lang.NullPointerException: println needs a message
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
            at android.app.ActivityThread.access$600(ActivityThread.java:141)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5041)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.NullPointerException: println needs a message
            at android.util.Log.println_native(Native Method)
            at android.util.Log.d(Log.java:138)
            at com.northstar.minimap.Communicator.getMapsJson(Communicator.java:53)
            at com.northstar.minimap.MapActivity.onCreate(MapActivity.java:36)
            at android.app.Activity.performCreate(Activity.java:5104)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
            at android.app.ActivityThread.access$600(ActivityThread.java:141)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5041)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
            at dalvik.system.NativeStart.main(Native Method)
11-19 08:02:50.933      308-445/system_process W/ActivityManager﹕ Force finishing activity com.northstar.minimap/.MapActivity
11-19 08:02:50.943      308-445/system_process W/ActivityManager﹕ Force finishing activity com.northstar.minimap/.MainActivity

The page it's querying (http://localhost:13980/api/maps/) is a simple GET endpoint that spits back some JSON. At this point, I'd just be happy if the JSON it pulled was printed to LogCat.

Thanks!

Benjin
  • 2,264
  • 2
  • 25
  • 50
  • 1
    What do you mean by "crashes"? How do you know it is crashing and what is the stack trace of any exceptions that are thrown? – Jason C Nov 19 '13 at 07:51
  • This does not solve your problem but improves exception handling: readStream should NOT catch the exception but specify it instead in its throws clause. – isnot2bad Nov 19 '13 at 08:07
  • @JasonC The app exits on the emulator, which displays a notification that says "Unfortunately, Minimap has stopped." I've updated the description with the stack trace. Looks like it's happening at the Log.d() call in getMapsJson's catch block. – Benjin Nov 19 '13 at 08:09
  • @isnot2bad so just throw the exception up to getMapsJson and let that method deal with it? – Benjin Nov 19 '13 at 08:09
  • Yes. Otherwise the calling method (getMapsJson) doesn't know that something bad has happened. – isnot2bad Nov 19 '13 at 08:14
  • All right; that's fixed. – Benjin Nov 19 '13 at 08:20
  • possible duplicate of [null pointer exception : println needs a message in android](http://stackoverflow.com/questions/6018633/null-pointer-exception-println-needs-a-message-in-android) – Jason C Nov 19 '13 at 08:35

2 Answers2

2

you're probably wrong with localhost, the server isn't running on the Android device or emulator itself.

you should use 10.0.2.2 to access the machine running an emulator, see http://developer.android.com/tools/devices/emulator.html

or the ip of the web server. (make sure its accessible to the outside world first)

as stated by @Jason C, your error handling is pretty bad. you should never catch all exceptions.

a pretty standard way is to make your method throw IOException, so the code calling getMapsJson can handle this particular and common exception (for example, no connectivity).

if you want to handle HTTP errors and errors code you should check the result code before opening an InputStream. In case of an error you can also get an ErrorStream instead of InputStream if you need the actual response in addition to the known result code.

Gal Ben-Haim
  • 17,433
  • 22
  • 78
  • 131
  • @Benjin: Even if this is your problem, you may want to improve your error handling code so that errors are properly displayed/logged. – Jason C Nov 19 '13 at 07:55
  • @JasonC could you elaborate? I only just (like, an hour ago) learned that I needed to use Log.d() instead of System.out.println to print stuff to the console, so please bear with me. – Benjin Nov 19 '13 at 08:11
  • @Gal Ben-Haim Makes sense. I don't suppose you'd happen to know how to expose whatever running at that port for localhost to 127.0.0.1:port (and therefore 10.0.2.2:port in the emulator)? – Benjin Nov 19 '13 at 08:16
  • @Benjin localhost and 127.0.0.1 are supposed to be the same, but if you have problems it probably depends on your OS, environment, etc.. please mark the answer as accepted. – Gal Ben-Haim Nov 19 '13 at 08:40
  • @GalBen-Haim What's the proper way to ice something on SO? I've got another SO question open to figure out the service exposure issue, and would like to come back to this question if/when the Android side still isn't working. – Benjin Nov 19 '13 at 12:46
0

The reason your app is (probably) throwing an exception is given in Gal Ben-haim's answer. However, the reason your app is crashing is because you are not properly handling the exception itself.

One tricky thing about exceptions is that getMessage() method can return null. Log.d() does not like the null parameter and so throws another exception out of your exception handler, which goes uncaught, and your application crashes and burns. Plus, your original exception is no longer part of the stack trace (since it wasn't the direct cause of the crash) and information about it is swallowed.

You should check if e.getMessage() is null and if it is, pass something non-null to Log.d (e.g. an empty string, perhaps).

See NullPointerException : println needs a message in android

Community
  • 1
  • 1
Jason C
  • 38,729
  • 14
  • 126
  • 182