Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
2.01 Add the Network Code
// These two need to be declared outside the try/catch
// so that they can be closed in the finally block.
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
// Will contain the raw JSON response as a string.
String forecastJsonStr = null;
try {
// Construct the URL for the OpenWeatherMap query
// Possible parameters are avaiable at OWM's forecast API page, at
URL url = new URL("");
// Create the request to OpenWeatherMap, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
forecastJsonStr = buffer.toString();
} catch (IOException e) {
Log.e("PlaceholderFragment", "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attemping
// to parse it.
return null;
} finally{
if (urlConnection != null) {
if (reader != null) {
try {
} catch (final IOException e) {
Log.e("PlaceholderFragment", "Error closing stream", e);
return rootView;

thanks for this help

thanks alot


Any reason why you are using StringBuffer instead of StringBuilder?

Also, nitpicking: the creation of the buffer could be better placed on line 28 instead of 22, because the buffer is needed only after checking that the input stream is not null.

thanks !

Good, thanks!

Thanks, this really helps a lot.


lyz1990 commented Mar 29, 2015


thank you!


ghost commented Apr 2, 2015

thanks a lot

MagoMtz commented Apr 3, 2015

why we use the GET method?

vdugnist commented Apr 4, 2015

MagoMtz: because we only want to get data from openweather, not to modify it. You can read about the difference between http methods on wikipedia:


In line 34 why to use a stringBuffer ? we can directly append to a string right?

npari commented Apr 5, 2015


The StringBuffer Class allows character representation that are mutable compared to the String class which is immutable. Also, concatenation is faster in StringBuffer. It is mainly a choice to improve performance. The concatenation operation using StringBuffer class and append makes it a cheaper operation.

ZikasR commented Apr 11, 2015


aindong commented Apr 24, 2015


mike915 commented Apr 24, 2015

Thanks, it helps a lot!

thanks !



shouldn't it be return null at the end of the script?

tunee commented May 13, 2015


Synix commented May 16, 2015


Haloyum commented May 20, 2015


Helps a lot.



ghost commented May 27, 2015

Thanks =)

Nice :)

88dave commented Jun 4, 2015

Good stuff -- useful for lots of situations

DeJaVo commented Jun 6, 2015

Great, thank for this useful code snippet

Great code!!!

dengn commented Jun 11, 2015

It's very possible that this code is running in multi-thread environment, StringBuffer is synchronized while StringBuilder is not.

Thanks for this!

Forgive me if this is a newbie question, but on line 23, when would the inputStream == null but not be triggered by an IOException? Follow up is that shouldn't the fact that nothing was received in the inputStream that wasn't generated from some exception be logged, if nothing else, for info/debug purposes?

Please help, i see on line 37 we are checking if the StringBuffer object "buffer" is equal to zero, but nothing was ever assigned to it, I'm i missing something? (i'm a newbie).

@osirivics line #34

Not to be a spelling nut but...


gomaa86 commented Jun 21, 2015

thank you for help :)

Thanks for the snippet :)

Isn't there a better way of doing this with the try with resources block instead? That away the streams are automatically closed

ikhfa commented Jul 1, 2015

Thanks for the snippet :)

saadeh05 commented Jul 1, 2015

I really don't understand most of the code
so is it normal not to understand it all or i'm missing something ?

I think it would be nice if you could understand it. But the Udacity course is aiming at the fresh man of Android development, and at this point the understanding of this code doesn't look that important.
So just learn how to use the snippet, and with the more code you read, you will get to understand it.

Thanks for the snippet :)

Thank you for Gist



Isn't there a better way of doing this with the try with resources block instead? That away the streams are automatically closed

I wondered about the same, so I searched a bit and according to what I understand, if you want to use try-with-resources statement (Java SE 7 feature), then you limit yourself to API 19: Android 4.4 (KitKat) and higher.

java 7 - Does Android support JDK 6 or 7 - Stack Overflow

Wsakr commented Jul 11, 2015

why do we have to call the setRequestMethod("GET") if the default of the HTTPURLConnection is GET

gishiru commented Jul 15, 2015


njsand commented Jul 16, 2015

@dengn Use of StringBuffer is wrong here. Even if multiple threads enter this method, they each allocate their own instance (because that's how "new" works), and this instance never "escapes" the method. Thus any internal synchronization that StringBuffer performs is completely wasted. So don't use it. StringBuilder is designed for exactly situations like this.

@njsand StringBuffer is fine here, and as stated above it has better performance for .append()
To the generation of extra strings on separate threads - I believe that is something you want. The response you get from any requests will be parsed on that thread (and added to that particular stringbuffer). The "threaded" part of networking is that the request posts and a thread that is not the UI thread handles the response and the parsing. This is how they do it in iOS also. To keep it from locking the UI.


Thank you!

du2x commented Aug 20, 2015


Hi All!

The URL in the code snipped gives me a city in Poland when I hand it to Chrome. I will try this URL for Mountain View - it seems to work in Chrome:,us&mode=json&units=metric&cnt=7

jhealy commented Aug 25, 2015

@jrmineur -
on edge in win10 - mountain view
On IE in win10 - montainview
On chrome in win10 - mountainview

Verified the following URL in Jason and xml formats -,us&mode=json&units=metric&cnt=7

Healy in Tampa

This is great!

Jorelx commented Aug 29, 2015


it's good. thanks

Thanks a lot!

Java has a try-with-resources, why android hasn't?
But question: why StringBuffer buffer = new StringBuffer(); doesn't under the inputStream != null checking? Here creates the buffer, and if an inputStream is null, there is work for CG, isn't it :)
Thanks anyway!

+1 for @njsand comment. The StringBuffer object is not shared between threads, it's totally "thread-confined", so there is no use in its thread-safety:)

@jrmineur and @jhealy using the zip parameter doesn't work for all zipcodes. I think getting the correct city every time involves getting the city id but that involves knowing the correct longitude and latitude.

Oh wow that is fairly simple. One newbie question, why do we return the rootView at the end? Also what is with all the extra "}" at the end? Thanks!

Thank you. The previous answer box didn't accept mode=JSON, but the API functioned properly with this parameter. Thanks again.

Should this be in "MainActivity" class or "MainActivityFragment" class?

zano5 commented Oct 8, 2015

MainActivity class

bahkali commented Oct 19, 2015

thank you. very explanatory

Thanks a lot!It's much helpful.

Why don't we do like this?

static String convertStreamToString( is) {
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? : "";

I am no Java programmer, but this is the first answer for InputStream to String

I just can't believe an InputStream would require 19 lines, 4 intermediary objects (buffer, reader, line, unnamed InputStreamReader) to convert it to a string.

Is it all for the sake of adding \n in between lines?

Another question, the json output from the query doesn't have lines. So where are we writing all those \n?

Thanks a lot, it's helpful .


Rolos commented Nov 22, 2015

I'm here too!

dandv commented Nov 25, 2015

Like @sebcagnon above, this low-level Java code makes my head hurt. The equivalent JavaScript code for the Meteor framework (which generates web and mobile apps from the same code base) is far, far simpler:

HTTP.get("", function (error, result) {
    if (error) {
    } else {
        let weatherData =;  // JSON automatically parsed

No need to get more complicated than what you actually want to do - get a JSON string via HTTP. Given that this course is aimed at beginners, it might have made more sense to use a high-level HTTP library such as Volley.

PS: no need to say "Thanks"; GitHub doesn't send notifications of activity on gists.

Amazing, thank you

i didnt get what is rootview the return type variable.It is a string right

don't forget to make comment in the url as the website needs id for now

I'm not exactly sure, but the correct url seems to be

Can't figure out what is q parameter being used, which is not mentioned in current API. And the present url gives a city in Poland. Basically because we have to use id now, and zip code is deprecated I guess.


ghost commented Dec 15, 2015

Consider this URL. When requesting postal codes use the 'zip' parameter. Also the new format for weather apis require an appid.

The codes presented in this course are not static. As the days go by, newer libraries are created and some codes become deprecated. It's up to you, the programmer, to debug the code that doesn't work.

nice 💃


Thanks a lot.

Guys, someone can help me?

I've gotten this error when I put my code on fragment, It's about async (I saw in StackOverflow) threads or some like that?

01-29 00:56:10.194 21852-21852/? E/AndroidRuntime: FATAL EXCEPTION: main
Process:, PID: 21852
java.lang.RuntimeException: Unable to start activity ComponentInfo{}: android.os.NetworkOnMainThreadException


why in my code error buffer not initialization ??

Why do we need a inputstream when we have a bufferdreader? Actually I am confused about this . Could someone please help?

In my competitive coding escapades I have used more complex form of input reading system which involved StringTokenizer etc. So this is not new to me. Why are we using these two? Well its because InputStreamReader takes byte stream and converts into one character at a time from input while BufferedReader then stores that and keeps buffering till a full line has been read. When this has been done we then just need to read our buffered string in one go. Without BufferedReader we will have to use a loop that stores everything in a char array character by character not a very efficient proposition. As for not using Scanner class I can't say if its the reason but in my experience Scanner class is terribly slow.

fzls commented Feb 2, 2016

thanks a lot!

@dengn @njsand @wahooka9
check below link. Looks like String Builder would be better choice.

AIRAT1 commented Feb 6, 2016

Herzlichen Dank!

@abhi007tyagi Thanks for the link 👍

TasneemS commented Feb 8, 2016

I think this code should be in the MainActivityFragment class in newer versions.

this given url in the code above is not working it showing a error page

Now that the OpenWeatherMap requires API key to make requests ( It should be (You can always paste it into your web browser to check the result).

mousaab commented Feb 14, 2016

It is true that the OpenWeatherMap requires API key
put any one can use this key:
so your URL should be like this ;

I cant believe that it takes 60 lines of code to make one GET request. I come from web background. We need 1 line there :(

beautiful code

@dandv @denkomanceski 👍 same feeling And I think more annoyingly, you don't see all of the try-catch blocks here.

Here is a simpler version.
how to send HttpRequest and get Json response in android?

HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget= new HttpGet(new URL(""));
String forecastJsonStr;

HttpResponse response = httpclient.execute(httpget);

   forecastJsonStr = EntityUtils.toString(response.getEntity());
} else {
   Log.i("Server response", "Failed to get server response" );

i recommend using volley is the best solution with few lines 👍
volley, Easy fast Networking library for android

Thanks !

This is my understanding of this code snippet,

We have to send a HTTP request to an URL and GET some data.


  • Create a new variable for the URL
    new URL(...)
  • Use the URL to create and open HttpURLConnection
  • Now send a GET request
  • If we get response for our request
    inputStream != null
    buffer the data and store it as a String.
    new BufferedReader()
  • And "finally" close the HttpURLConnection

Simply as open, request, response, close.

Instead of (buffer.length() == 0) can we write (buffer == null). Please explain.

Thank you very much!!!

wilik16 commented Mar 16, 2016

@Ashwin-Kapes you can't, because the buffer is instantiated already = new StringBuffer(); thus not null.

saber01 commented Mar 16, 2016

thank u

Thank You

I am getting error following error

Executing tasks: [:app:assembleDebug]

Configuration on demand is an incubating feature.
:app:preBuild UP-TO-DATE
:app:preDebugBuild UP-TO-DATE
:app:preReleaseBuild UP-TO-DATE
:app:prepareComAndroidSupportAnimatedVectorDrawable2321Library UP-TO-DATE
:app:prepareComAndroidSupportAppcompatV72321Library UP-TO-DATE
:app:prepareComAndroidSupportDesign2321Library UP-TO-DATE
:app:prepareComAndroidSupportRecyclerviewV72321Library UP-TO-DATE
:app:prepareComAndroidSupportSupportV42321Library UP-TO-DATE
:app:prepareComAndroidSupportSupportVectorDrawable2321Library UP-TO-DATE
:app:prepareComGoogleAndroidGmsPlayServicesAppindexing810Library UP-TO-DATE
:app:prepareComGoogleAndroidGmsPlayServicesBasement810Library UP-TO-DATE
:app:compileDebugAidl UP-TO-DATE
:app:compileDebugRenderscript UP-TO-DATE
:app:generateDebugBuildConfig UP-TO-DATE
:app:generateDebugAssets UP-TO-DATE
:app:mergeDebugAssets UP-TO-DATE
:app:generateDebugResValues UP-TO-DATE
:app:generateDebugResources UP-TO-DATE
:app:mergeDebugResources UP-TO-DATE
:app:processDebugManifest UP-TO-DATE
:app:processDebugResources UP-TO-DATE
:app:generateDebugSources UP-TO-DATE
/home/yodgorbek/AndroidStudioProjects/Sunshine/app/src/main/java/com/example/android/sunshine/ error: non-static method getInputStream() cannot be referenced from a static context
InputStream inputStream = URLConnection.getInputStream();
Note: /home/yodgorbek/AndroidStudioProjects/Sunshine/app/src/main/java/com/example/android/sunshine/ uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
1 error


FAILURE: Build failed with an exception.

  • What went wrong:
    Execution failed for task ':app:compileDebugJavaWithJavac'.

    Compilation failed; see the compiler error output for details.

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.


Total time: 1.303 secs

Google + Udacity = Best Combination ever.... Thanks for all, Very intuitive way to teach

Thank you, That is great

JLundho commented Mar 27, 2016

To mix it up and simplify the networking tasks, I used OkHttp to perform the network request (which also reduced the boilerplate), but this resulted in an exception saying that I was attempting to perform network operations on the main thread. Did this always create an exception?
If you stumble onto the same problem, use AsyncTask and remember to request the appropriate permissions.



Nicofisi commented Apr 9, 2016

Great ^^

@Nicofisi and @Danihelsan if possible please share your snippet I am getting error

04-12 20:31:01.652 5740-5740/ E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                      java.lang.RuntimeException: Unable to start activity ComponentInfo{}: android.view.InflateException: Binary XML file line #1: Error inflating class fragment
                                                                                          at android.os.Handler.dispatchMessage(
                                                                                          at android.os.Looper.loop(
                                                                                          at java.lang.reflect.Method.invokeNative(Native Method)
                                                                                          at java.lang.reflect.Method.invoke(
                                                                                          at dalvik.system.NativeStart.main(Native Method)
                                                                                       Caused by: android.view.InflateException: Binary XML file line #1: Error inflating class fragment
                                                                                          at android.view.LayoutInflater.createViewFromTag(
                                                                                          at android.view.LayoutInflater.parseInclude(
                                                                                          at android.view.LayoutInflater.rInflate(
                                                                                          at android.view.LayoutInflater.inflate(
                                                                                          at android.view.LayoutInflater.inflate(
                                                                                          at android.view.LayoutInflater.inflate(
                                                                                          at android.os.Handler.dispatchMessage( 
                                                                                          at android.os.Looper.loop( 
                                                                                          at java.lang.reflect.Method.invokeNative(Native Method) 
                                                                                          at java.lang.reflect.Method.invoke( 
                                                                                          at dalvik.system.NativeStart.main(Native Method) 
                                                                                       Caused by: android.os.NetworkOnMainThreadException
                                                                                          at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(
                                                                                          at android.view.LayoutInflater.createViewFromTag(

ronengi commented Apr 14, 2016



miriban commented Apr 16, 2016


@PrafullaKumarSahu ... i think is related to yout fragment initialization, besides, have you reviewed the http response of the query?
i just copied that snippet and it works :)


ghost commented May 7, 2016



progdog commented May 23, 2016

Thank you very much!

mur7ay commented May 23, 2016

@PrafullaKumarSahu Did you figure it out or do you still need help?


i get errors in all "return null;" lines

windog commented Jun 2, 2016

Awesome!!thanks a lot.
but the Http request method was changed.
Now you can use the following address:{your APPID}

rajat1saxena commented Jun 2, 2016

I would suggest users to replace line 34 with the following

buffer.append(line).append("\n"); // Replaced string concatenation inside append

As string concatenation inside buffer.append() will lead to the creation of yet another StringBuffer on the fly, which degrades performance. It is a good practice to avoid string concatenation inside loops (read more about it in an awesome book: Effective Java)

Thanks a lot!

Clumsy-Coder commented Jun 20, 2016

I had a problem executing the code from the snippet above. Turns out it was NetworkOnMainThreadException. Which means the network access has occured in the main thread. Which is highly discouraged. I have found a small work around. This is a dirty approach. It should be only used for checking if the code works. Here is my solution.

The following code is in the onCreateView(LayoutInflator, ViewGroup, Bundle) method in the PlaceholderFragment subclass:

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitNetwork().build();

The following is in the AndroidManifest.xml file.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
The two xml elements are placed as a child of manifest and are siblings to the application element

The same can be achieved with the following code:

String forecastJsonStr = null;
URL url = new URL("");
try {

          OkHttpClient client = new OkHttpClient();
          Request request = new Request.Builder().url(url).build();
          response = client.newCall(request).execute();
          forecastJsonStr = response.body().string();

           } catch (IOException e) {
            return forecastJsonStr;

For above to work, you have to add following line to your gradle:

compile {
     compile 'com.squareup.okhttp3:okhttp:3.4.1'

i am just new to android
when i add this code into new file there i am having error for rootView.
inside of doInBackGround its saying rootView is undefined although all this code is still part of Fragment.
Any Suggestion?

Thanks a lot!

Alreco commented Aug 2, 2016

Thanks a lot!

Why we are using StringBuffer ?


cool =) Tks


Claiger commented Sep 3, 2016

So I'm getting the same error that PrafullaKumarSahu was getting. I'm not sure what the reason is. I saw the comment about the dirty approach but I'd rather have some sort of fix I can maintain in the system. I'm trying to publish my code to Github and am having problems so in the meantime I'll pose the question.


Thanks! a nice code to teach basics

alextudu commented Oct 2, 2016

Great Code!

porzioj commented Oct 3, 2016


hvubio commented Oct 11, 2016


Thanks a lot!

Thanks! =]




Thank you!

Miltex commented Jan 14, 2017

Cool :D

@Clumsy-Coder your comment was super helpful! I had the same problem and couldn't figure out why earlier!

lephleg commented Dec 10, 2017

The daily forecast has been removed for the free subscibers. Try to use 5 days 3 hour forecast endpoint instead:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment