teaching machines

Homework #3 crakerbr

November 4, 2011 by . Filed under cs491 mobile, fall 2011, postmortems.

Everybody faces a daily decision to either go and do something outside or stay home and play video games. Rather than trying to estimate the weather and risk frostbite, heatstroke, hypothermia, or any of the other afflictions nature tries to kill us with, my app finds out the current weather and tells you whether to venture outside or stay safely inside.

The app uses the Wunderground API to get current weather data, which returns information in a JSON string. To access the API, I needed to get a developer’s key, which is hardcoded into my program. The key was free (I had to register my email), but limited in the amount of requests I can make per minute. There is a pay-for system to reduce limitations, but the free one certainly fit my needs.

The request is made via the creation of a simple service, which supplies the API key and zipcode to query data for. The onReceiveResult method in the main activity uses the data when it is available, reporting the status of the network query, the weather condition, and the current temperature. It then makes the determination of whether the user should go outside or stay indoors. The user is only advised to go outside if the weather is clear and the temperature is between 65 and 80 degrees Fahrenheit.

The main view also displays an image supplied by Wundergound indicating the current conditions. The JSON results include a URL for the icon, with is fetched and set with the following code:

// Download the image void download_file(String s) {   URL url = null;   try {     url = new URL(s);   } catch(MalformedURLException e) {     e.printStackTrace();   } try {     HttpURLConnection conn = (HttpURLConnection)url.openConnection();     conn.setDoInput(true);     conn.connect();     InputStream is = conn.getInputStream();     bm = BitmapFactory.decodeStream(is);     condition_img.setImageBitmap(bm);   } catch(IOException e) {     e.printStackTrace();   } }

The app defaults to displaying data in Fahrenheit for the zip code 54701 (in Eau Claire), but the user can change that by clicking “Edit Settings” at the bottom of the main view. The settings are stored in a flat file on the phone, encoded in JSON format. Writing to a file on Android is similar to standard Java methods, except the context must be supplied. Here is my code to read and write to my file:

// Save the settings to the settings.json file public void save_settings(Context c) {   try {     JSONObject j = new JSONObject();     j.put("zipcode", this.zipcode);     j.put("celsius", this.celsius);     String s = j.toString();     FileOutputStream out = c.openFileOutput(file, Context.MODE_WORLD_READABLE);     OutputStreamWriter osw = new OutputStreamWriter(out);     osw.write(s);     osw.flush();     osw.close();   } catch(JSONException e) {     e.printStackTrace();   } catch(IOException ioe) {     ioe.printStackTrace();   } } // Load the settings from the settings.json file public String load_settings(Context c) {   String json = "";   try {     FileInputStream in = c.openFileInput(file);     InputStreamReader isr = new InputStreamReader(in);     char[] buf = new char[1024];     isr.read(buf);     json = new String(buf);     JSONObject j = new JSONObject(json);     this.zipcode = j.getString("zipcode");     this.celsius = j.getBoolean("celsius");   } catch(IOException ioe) {     ioe.printStackTrace();   } catch(JSONException e) {     e.printStackTrace();   }   return json; }

A minor hurdle I ran into was getting the “spinner” to show the value currently stored in the settings. I use the spinner to allow the user to choose either Fahrenheit or Celsius for temperature displays, and when the user calls up the settings I wanted them to see the currently selected value. The code to accomplish this is as follows:

String[] spinner_list = new String[2]; spinner_list[0] = "Celsius"; spinner_list[1] = "Fahrenheit"; final Spinner temperature_variable = (Spinner)findViewById(R.id.temperature_variable); @SuppressWarnings({ "unchecked", "rawtypes" }) ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, spinner_list); temperature_variable.setAdapter(adapter); if(s.isCelsius()) {   temperature_variable.setSelection(0); } else {   temperature_variable.setSelection(1); }

The user then is able to Save the settings or Cancel the edit.