Weather

We downloaded data from this server in Weather. See that app for printouts of the JSON that came from the server.

The download in this app had to be performed in the second thread, not in the UI thread, because it might take several seconds. But there is no reason that the current version of this app has to parse the JSON in the second thread. But I’m doing it in the sceond thread to make it easier to do the icon exercise. The JSON has to be parsed in order to get the names of the icon files, and the icon files can’t be downloaded by the UI thread, Parsing the JSON in the second thread makes it possible for the cons to be downloaded in the second thread.

In the project Offer, the GridView was fed by a SimpleCursorAdapter; see that project’s gridview_item.xml file. In the project GridView, the GridView was fed by an adapter we wrote ourselves. We couldn’t use a SimpleCursorAdapter because we had no cursor. And we couldn’t use an ArrayAdapter, because an ArrayAdapter always creates TextViews.

In the project Weather, we downloaded JSON from openweathermap.org.

Source code in WeatherGrid.zip

  1. MainActivity.java. Class MainActivity contains the inner class DownloadTask.
  2. ReportAdapter.java.
  3. activity_main.xml is a RelativeLayout containing a GridView.
  4. gridview_item.xml is a vertical LinearLayout containing three TextViews and eventually an ImageView.
  5. strings.xml
  6. dimens.xml
  7. AndroidManifest.xml has uses-permission INTERNET.
  8. build.gradle (Module: app).

Create the project

In the Android Studio project view, select the layout folder.
File → New → XML → Layout XML File
Layout File Name: gridview_item
Root Tag: LinearLayout
Finish

Things to Try

  1. Add the icons.
    1. Add the following to the LinearLayout in gridview_item.xml.
          <ImageView
              android:id="@+id/icon"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"/>
      
    2. Add a fourth field to class DownloadTask. A Bitmap holds the rows and columns of pixels that can be displayed by an ImageView.
          Bitmap[] bitmap = new Bitmap[7];
      
    3. In the doInBackground method of class DownloadTask, immediately after the
                          humidity[i] = day.getInt("humidity");
      
      insert the following.
                          JSONArray weather = day.getJSONArray("weather");
                          JSONObject w = (JSONObject)weather.get(0);
                          String icon = w.getString("icon");
      
                          HttpURLConnection connection = null;
                          InputStream inputStream = null;
                          byte[] byteArray = null;
      
                          try {
                              URL url = new URL("http://openweathermap.org/img/w/" + icon + ".png");
                              connection = (HttpURLConnection)url.openConnection();
                              connection.setRequestMethod("GET");
                              connection.setDoInput(true);
                              connection.connect();
      
                              // Read the response.
                              inputStream = connection.getInputStream();
                              byte[] buffer = new byte[1024];
                              ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
      
                              while (inputStream.read(buffer) != -1) {
                                  outputStream.write(buffer);
                              }
                              byteArray = outputStream.toByteArray();
                          } catch (Exception exception) {
                              Log.e("myTag", "doInBackground", exception);
                          }
                          finally {
                              try {
                                  inputStream.close();
                              } catch(Exception exception) {
                                  Log.e("myTag", "doInBackground", exception);
                                  return null;
                              }
                              try {
                                  connection.disconnect();
                              } catch(Exception exception) {
                                  Log.e("myTag", "doInBackground", exception);
                                  return null;
                              }
                          }
                          if (byteArray != null && byteArray.length > 0) {
                              bitmap[i] = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
                          }
      
    4. In the onPostExecute method of class DownloadTask, add one more argument to the follwing constructor.
                  ReportAdapter reportAdapter = new ReportAdapter(MainActivity.this, date, humidity, temperature, bitmap);
      
    5. Add the following field to class ReportAdapter.
          Bitmap[] bitmap;
      
      Initialize the new field in the ReportAdapter constructor.
          public ReportAdapter(/* four existing arguments */, Bitmap[] bitmap) {
              this.context = context;
              //etc.
              this.bitmap = bitmap;
          }
      
    6. Insert the following into the getView method of class ReportAdapter immediately before the return.
              ImageView imageView = (ImageView)linearLayout.findViewById(R.id.icon);
              imageView.setImageBitmap(bitmap[position]);
      

  2. Each icon is 50 × 50 pixels. For example, I drew an outline around http://openweathermap.org/img/w/01d.png

    A simple way to change the size of the icon is to set the layout_width and layout_height of the ImageView in gridview_item.xml to 50dp.

  3. Instead of downloading the icons as the app is running, download them before you write the app and copy them into the drawable folder of the res folder. Give the files names that start with a letter, e.g., icon01d.png. The array of seven BitMaps will become an array of seven Strings containing strings such as "01d" or "01n" (for “day” or “night”). The last argument of the constructor of ReportAdapter, and the field you added to this class, will also become Strings; rename the field to icon. The getView method of the ReportAdapter will say something like the following.
            if (icon.equals("01d") {
                imageView.setImageResource(R.drawable.icon01d);
            } else if (icon.equals("01n") {
                //etc.
    
    There are 18 icons. What are the tradeoffs between download-before vs. download during execution?

  4. Display a dialog inviting the user tp type in their zipcode. Then show the wethare for that zipcode.