Advertisement
Guest User

Untitled

a guest
Jul 8th, 2015
263
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.06 KB | None | 0 0
  1. /*
  2. * Copyright (C) 2014 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.example.android.sunshine.app;
  17.  
  18. import android.content.Intent;
  19. import android.net.Uri;
  20. import android.os.AsyncTask;
  21. import android.os.Bundle;
  22. import android.support.v4.app.Fragment;
  23. import android.text.format.Time;
  24. import android.util.Log;
  25. import android.view.Gravity;
  26. import android.view.LayoutInflater;
  27. import android.view.Menu;
  28. import android.view.MenuInflater;
  29. import android.view.MenuItem;
  30. import android.view.View;
  31. import android.view.ViewGroup;
  32. import android.widget.AdapterView;
  33. import android.widget.ArrayAdapter;
  34. import android.widget.ListView;
  35. import android.widget.Toast;
  36.  
  37. import org.json.JSONArray;
  38. import org.json.JSONException;
  39. import org.json.JSONObject;
  40.  
  41. import java.io.BufferedReader;
  42. import java.io.IOException;
  43. import java.io.InputStream;
  44. import java.io.InputStreamReader;
  45. import java.net.HttpURLConnection;
  46. import java.net.URL;
  47. import java.text.SimpleDateFormat;
  48. import java.util.ArrayList;
  49. import java.util.Arrays;
  50. import java.util.List;
  51.  
  52. /**
  53. * Encapsulates fetching the forecast and displaying it as a {@link ListView} layout.
  54. */
  55. public class ForecastFragment extends Fragment {
  56.  
  57. private ArrayAdapter<String> mForecastAdapter;
  58.  
  59. public ForecastFragment() {
  60. }
  61.  
  62. @Override
  63. public void onCreate(Bundle savedInstanceState) {
  64. super.onCreate(savedInstanceState);
  65. // Add this line in order for this fragment to handle menu events.
  66. setHasOptionsMenu(true);
  67. }
  68.  
  69. @Override
  70. public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
  71. inflater.inflate(R.menu.forecastfragment, menu);
  72. }
  73.  
  74. @Override
  75. public boolean onOptionsItemSelected(MenuItem item) {
  76. // Handle action bar item clicks here. The action bar will
  77. // automatically handle clicks on the Home/Up button, so long
  78. // as you specify a parent activity in AndroidManifest.xml.
  79. int id = item.getItemId();
  80. if (id == R.id.action_refresh) {
  81. FetchWeatherTask weatherTask = new FetchWeatherTask();
  82. weatherTask.execute("istanbul");
  83. return true;
  84. }
  85. return super.onOptionsItemSelected(item);
  86. }
  87.  
  88. @Override
  89. public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  90.  
  91. // Now that we have some dummy forecast data, create an ArrayAdapter.
  92. // The ArrayAdapter will take data from a source (like our dummy forecast) and
  93. // use it to populate the ListView it's attached to.
  94. mForecastAdapter =
  95. new ArrayAdapter<String>(
  96. getActivity(), // The current context (this activity)
  97. R.layout.list_item_forecast, // The name of the layout ID.
  98. R.id.list_item_forecast_textview, // The ID of the textview to populate.
  99. new ArrayList<String>());
  100.  
  101. View rootView = inflater.inflate(R.layout.fragment_main, container, false);
  102.  
  103. // Get a reference to the ListView, and attach this adapter to it.
  104. ListView listView = (ListView) rootView.findViewById(R.id.listview_forecast);
  105. listView.setAdapter(mForecastAdapter);
  106.  
  107. listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  108. @Override
  109. public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
  110. String forecast = mForecastAdapter.getItem(position);
  111. Intent intent = new Intent(getActivity(), DetailActivity.class);
  112. intent.putExtra(Intent.EXTRA_TEXT, forecast);
  113. startActivity(intent);
  114. }
  115. });
  116.  
  117. return rootView;
  118. }
  119.  
  120. public class FetchWeatherTask extends AsyncTask<String, Void, String[]> {
  121.  
  122. private final String LOG_TAG = FetchWeatherTask.class.getSimpleName();
  123.  
  124. /* The date/time conversion code is going to be moved outside the asynctask later,
  125. * so for convenience we're breaking it out into its own method now.
  126. */
  127. private String getReadableDateString(long time) {
  128. // Because the API returns a unix timestamp (measured in seconds),
  129. // it must be converted to milliseconds in order to be converted to valid date.
  130. SimpleDateFormat shortenedDateFormat = new SimpleDateFormat("EEE MMM dd");
  131. return shortenedDateFormat.format(time);
  132. }
  133.  
  134. /**
  135. * Prepare the weather high/lows for presentation.
  136. */
  137. private String formatHighLows(double high, double low) {
  138. // For presentation, assume the user doesn't care about tenths of a degree.
  139. long roundedHigh = Math.round(high);
  140. long roundedLow = Math.round(low);
  141.  
  142. String highLowStr = roundedHigh + "/" + roundedLow;
  143. return highLowStr;
  144. }
  145.  
  146. /**
  147. * Take the String representing the complete forecast in JSON Format and
  148. * pull out the data we need to construct the Strings needed for the wireframes.
  149. * <p/>
  150. * Fortunately parsing is easy: constructor takes the JSON string and converts it
  151. * into an Object hierarchy for us.
  152. */
  153. private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays)
  154. throws JSONException {
  155.  
  156. // These are the names of the JSON objects that need to be extracted.
  157. final String OWM_LIST = "list";
  158. final String OWM_WEATHER = "weather";
  159. final String OWM_TEMPERATURE = "temp";
  160. final String OWM_MAX = "max";
  161. final String OWM_MIN = "min";
  162. final String OWM_DESCRIPTION = "main";
  163.  
  164. JSONObject forecastJson = new JSONObject(forecastJsonStr);
  165. JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);
  166.  
  167. // OWM returns daily forecasts based upon the local time of the city that is being
  168. // asked for, which means that we need to know the GMT offset to translate this data
  169. // properly.
  170.  
  171. // Since this data is also sent in-order and the first day is always the
  172. // current day, we're going to take advantage of that to get a nice
  173. // normalized UTC date for all of our weather.
  174.  
  175. Time dayTime = new Time();
  176. dayTime.setToNow();
  177.  
  178. // we start at the day returned by local time. Otherwise this is a mess.
  179. int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff);
  180.  
  181. // now we work exclusively in UTC
  182. dayTime = new Time();
  183.  
  184. String[] resultStrs = new String[numDays];
  185. for (int i = 0; i < weatherArray.length(); i++) {
  186. // For now, using the format "Day, description, hi/low"
  187. String day;
  188. String description;
  189. String highAndLow;
  190.  
  191. // Get the JSON object representing the day
  192. JSONObject dayForecast = weatherArray.getJSONObject(i);
  193.  
  194. // The date/time is returned as a long. We need to convert that
  195. // into something human-readable, since most people won't read "1400356800" as
  196. // "this saturday".
  197. long dateTime;
  198. // Cheating to convert this to UTC time, which is what we want anyhow
  199. dateTime = dayTime.setJulianDay(julianStartDay + i);
  200. day = getReadableDateString(dateTime);
  201.  
  202. // description is in a child array called "weather", which is 1 element long.
  203. JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
  204. description = weatherObject.getString(OWM_DESCRIPTION);
  205.  
  206. // Temperatures are in a child object called "temp". Try not to name variables
  207. // "temp" when working with temperature. It confuses everybody.
  208. JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE);
  209. double high = temperatureObject.getDouble(OWM_MAX);
  210. double low = temperatureObject.getDouble(OWM_MIN);
  211.  
  212. highAndLow = formatHighLows(high, low);
  213. resultStrs[i] = day + " - " + description + " - " + highAndLow;
  214. }
  215.  
  216. return resultStrs;
  217.  
  218. }
  219.  
  220. @Override
  221. protected void onPostExecute(String[] result) {
  222. if (result != null){
  223. mForecastAdapter.clear();
  224. for (String dayForecastStr : result){
  225. mForecastAdapter.add(dayForecastStr);
  226. }
  227.  
  228. }
  229.  
  230. }
  231.  
  232. @Override
  233. protected String[] doInBackground(String... params) {
  234.  
  235. // If there's no zip code, there's nothing to look up. Verify size of params.
  236. if (params.length == 0) {
  237. return null;
  238. }
  239.  
  240. // These two need to be declared outside the try/catch
  241. // so that they can be closed in the finally block.
  242. HttpURLConnection urlConnection = null;
  243. BufferedReader reader = null;
  244.  
  245. // Will contain the raw JSON response as a string.
  246. String forecastJsonStr = null;
  247.  
  248. String format = "json";
  249. String units = "metric";
  250. int numDays = 7;
  251.  
  252. try {
  253. // Construct the URL for the OpenWeatherMap query
  254. // Possible parameters are avaiable at OWM's forecast API page, at
  255. // http://openweathermap.org/API#forecast
  256. final String FORECAST_BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily?";
  257. final String QUERY_PARAM = "q";
  258. final String FORMAT_PARAM = "mode";
  259. final String UNITS_PARAM = "units";
  260. final String DAYS_PARAM = "cnt";
  261.  
  262. Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
  263. .appendQueryParameter(QUERY_PARAM, params[0])
  264. .appendQueryParameter(FORMAT_PARAM, format)
  265. .appendQueryParameter(UNITS_PARAM, units)
  266. .appendQueryParameter(DAYS_PARAM, Integer.toString(numDays))
  267. .build();
  268.  
  269. URL url = new URL(builtUri.toString());
  270.  
  271. // Create the request to OpenWeatherMap, and open the connection
  272. urlConnection = (HttpURLConnection) url.openConnection();
  273. urlConnection.setRequestMethod("GET");
  274. urlConnection.connect();
  275.  
  276. // Read the input stream into a String
  277. InputStream inputStream = urlConnection.getInputStream();
  278. StringBuffer buffer = new StringBuffer();
  279. if (inputStream == null) {
  280. // Nothing to do.
  281. return null;
  282. }
  283. reader = new BufferedReader(new InputStreamReader(inputStream));
  284.  
  285. String line;
  286. while ((line = reader.readLine()) != null) {
  287. // Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
  288. // But it does make debugging a *lot* easier if you print out the completed
  289. // buffer for debugging.
  290. buffer.append(line + "\n");
  291. }
  292.  
  293. if (buffer.length() == 0) {
  294. // Stream was empty. No point in parsing.
  295. return null;
  296. }
  297. forecastJsonStr = buffer.toString();
  298.  
  299. } catch (IOException e) {
  300. Log.e(LOG_TAG, "Error ", e);
  301. // If the code didn't successfully get the weather data, there's no point in attemping
  302. // to parse it.
  303. return null;
  304. } finally {
  305. if (urlConnection != null) {
  306. urlConnection.disconnect();
  307. }
  308. if (reader != null) {
  309. try {
  310. reader.close();
  311. } catch (final IOException e) {
  312. Log.e(LOG_TAG, "Error closing stream", e);
  313. }
  314. }
  315. }
  316.  
  317. try {
  318. return getWeatherDataFromJson(forecastJsonStr, numDays);
  319. } catch (JSONException e) {
  320. Log.e(LOG_TAG, e.getMessage(), e);
  321. e.printStackTrace();
  322. }
  323.  
  324. // This will only happen if there was an error getting or parsing the forecast.
  325. return null;
  326. }
  327. }
  328. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement