Android Open Source - Android_Sunshine_Tutorial Forecast Fragment






From Project

Back to project page Android_Sunshine_Tutorial.

License

The source code is released under:

GNU General Public License

If you think the Android project Android_Sunshine_Tutorial listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.example.androidtutorialsunshine;
// ww  w  .j  a v a2  s .  c  o m
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Fragment;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;

/**
 * A placeholder fragment containing a simple view.
 */
public class ForecastFragment extends Fragment {

  private ArrayAdapter<String> mForecastAdapter;
  
  //Constructor
  public ForecastFragment() {
  }
  
  
  //What to do if the menu option is clicked
  public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
    super.onCreateOptionsMenu(menu, inflater);
      //menu.clear();
    inflater.inflate(R.menu.forecast_fragment, menu);
  }
  
  //Items clicked within the menu
  public boolean onOptionsItemSelected(MenuItem item){
    int id = item.getItemId();
    if (id == R.id.action_refresh){
      FetchWeatherTask weatherTask = new FetchWeatherTask();
      weatherTask.execute();
      return true;
    }
    
    return super.onOptionsItemSelected(item);
    
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    
    setHasOptionsMenu(true);
    
    View rootView = inflater.inflate(R.layout.fragment_main_activity8, container, false);
    
    
    String [] forecastArray={
        "Today - Sunny - 88/64",
        "Tomorrow - Rainy - 55/ 44"
    };
    
    List<String> weekForecast = new ArrayList<String>(Arrays.asList(forecastArray));
   
    //Array adapter will take the source data and populate the listview we attach it to
    mForecastAdapter = new ArrayAdapter<String>(
        //Current activity
        getActivity(),
        //IT of the list item layout
        R.layout.list_item_forecast,
        //ID of the textview to populate
        R.id.list_item_forecast_textview,
        //Forecast data itself
        weekForecast);
        
    //Get a reference to the listview and then attach the adapter
    ListView listView = (ListView) rootView.findViewById(R.id.listview_forecast);
    listView.setAdapter(mForecastAdapter);

    return rootView;
  }
  
  //Fetch the weather data from a server
  public class FetchWeatherTask extends AsyncTask<String, Void, String[]>{

    private final String LOG_TAG = FetchWeatherTask.class.getSimpleName();


    /* The date/time conversion code is going to be moved outside the asynctask later,
     * so for convenience we're breaking it out into its own method now.
     */
    private String getReadableDateString(long time){
        // Because the API returns a unix timestamp (measured in seconds),
        // it must be converted to milliseconds in order to be converted to valid date.
        Date date = new Date(time * 1000);
        SimpleDateFormat format = new SimpleDateFormat("E, MMM d");
        return format.format(date).toString();
    }
     
    /**
     * Prepare the weather high/lows for presentation.
     */
    private String formatHighLows(double high, double low) {
        // For presentation, assume the user doesn't care about tenths of a degree.
        long roundedHigh = Math.round(high);
        long roundedLow = Math.round(low);
     
        String highLowStr = roundedHigh + "/" + roundedLow;
        return highLowStr;
    }
     
    /*
     * Take the String representing the complete forecast in JSON Format and
     * pull out the data we need to construct the Strings needed for the wireframes.
     *
     * Fortunately parsing is easy:  constructor takes the JSON string and converts it
     * into an Object hierarchy for us.
     */
    private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays)
            throws JSONException {
     
        // These are the names of the JSON objects that need to be extracted.
        final String OWM_LIST = "list";
        final String OWM_WEATHER = "weather";
        final String OWM_TEMPERATURE = "temp";
        final String OWM_MAX = "max";
        final String OWM_MIN = "min";
        final String OWM_DATETIME = "dt";
        final String OWM_DESCRIPTION = "main";
     
        JSONObject forecastJson = new JSONObject(forecastJsonStr);
        JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);
     
        String[] resultStrs = new String[numDays];
        for(int i = 0; i < weatherArray.length(); i++) {
            // For now, using the format "Day, description, hi/low"
            String day;
            String description;
            String highAndLow;
     
            // Get the JSON object representing the day
            JSONObject dayForecast = weatherArray.getJSONObject(i);
     
            // The date/time is returned as a long.  We need to convert that
            // into something human-readable, since most people won't read "1400356800" as
            // "this saturday".
            long dateTime = dayForecast.getLong(OWM_DATETIME);
            day = getReadableDateString(dateTime);
     
            // description is in a child array called "weather", which is 1 element long.
            JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
            description = weatherObject.getString(OWM_DESCRIPTION);
     
            // Temperatures are in a child object called "temp".  Try not to name variables
            // "temp" when working with temperature.  It confuses everybody.
            JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE);
            double high = temperatureObject.getDouble(OWM_MAX);
            double low = temperatureObject.getDouble(OWM_MIN);
     
            highAndLow = formatHighLows(high, low);
            resultStrs[i] = day + " - " + description + " - " + highAndLow;
        }
        
        for (String s : resultStrs){
          Log.v(LOG_TAG, "Forecast Entry: " + s);
        }
     
        return resultStrs;
    }
    
    @Override
    protected String[] doInBackground(String... params) {
      
      //Check parameter length first to confirm passed in var
      if (params.length == 0){
        return null;
      }
      
      //Declare these outside of the try catch so it can be closed via the finally
      HttpURLConnection urlConnection = null;
      BufferedReader reader = null;
      
      // Will contain the raw JSON response as a string.
      String forecastJsonStr = null;
      
      String format = "json";
      String units = "metric";
      int numDays = 7;
      
      try {
          // Construct the URL for the OpenWeatherMap query
          // Possible parameters are avaiable at OWM's forecast API page, at
          // http://openweathermap.org/API#forecast
        
        final String FORECAST_BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily";
        final String QUERY_PARAM = "q";
        final String FORMAT_PARAM = "mode";
        final String UNITS_PARAM = "units";
        final String DAYS_PARAM = "cnt";
        
        //Build the URI via the params and strings above
        Uri builtURI = Uri.parse(FORECAST_BASE_URL).buildUpon()
            .appendQueryParameter(QUERY_PARAM, params[0])
            .appendQueryParameter(FORMAT_PARAM, format)
            .appendQueryParameter(UNITS_PARAM, units)
            .appendQueryParameter(DAYS_PARAM, Integer.toString(numDays))
            .build();
        
        //Create the finalized URL
          URL url = new URL(builtURI.toString());
          
          //Log the results for debugging
          Log.v(LOG_TAG, "Built URI: " + builtURI.toString());
          
       
          
          
          
          // Create the request to OpenWeatherMap, and open the connection
          urlConnection = (HttpURLConnection) url.openConnection();
          urlConnection.setRequestMethod("GET");
          urlConnection.connect();
       
          // Read the input stream into a String
          InputStream inputStream = urlConnection.getInputStream();
          StringBuffer buffer = new StringBuffer();
          
          if (inputStream == null) {
              // Nothing to do.
              forecastJsonStr = null;
              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.
              forecastJsonStr = null;
          }
          forecastJsonStr = buffer.toString();
          
          Log.v(LOG_TAG, "Forecast String: " + forecastJsonStr);
          
      } catch (IOException e) {
          Log.e(LOG_TAG, "Error ", e);
          // If the code didn't successfully get the weather data, there's no point in attempting to parse it.
          return null;
          
      } finally{
          if (urlConnection != null) {
              urlConnection.disconnect();
          }
          if (reader != null) {
              try {
                  reader.close();
              } catch (final IOException e) {
                  Log.e(LOG_TAG, "Error closing stream", e);
              }
          }
      }
      
      try{
        return getWeatherDataFromJson(forecastJsonStr, numDays);
      } catch (JSONException e){
        Log.e(LOG_TAG, e.getMessage(), e);
        e.printStackTrace();
      }
      
      return null;
    }

    @Override
    protected void onPostExecute(String[] result) {
      super.onPostExecute(result);
      
      if (result != null){
        //Clear if of previous entries (IE hard coded ones)
        mForecastAdapter.clear();
        
        for(String dayForecastStr : result){
          mForecastAdapter.add(dayForecastStr);
        }
        //Data has been retrieved from the server at this point
      }
    }  
  }
}




Java Source Code List

com.example.androidtutorialsunshine.ForecastFragment.java
com.example.androidtutorialsunshine.MainActivity8.java
com.example.androidtutorialsunshine.SettingsActivity.java
com.example.androidtutorialsunshine.WeatherDataParser.java
com.pgmacdesign.androidtutorialsunshine.ApplicationTest.java
com.pgmacdesign.androidtutorialsunshine.MainActivity6.java