2016-06-03 2 views
0

ForecastFragment.javaПроект Sunshine: данные не обновляются после обновления приложения?

// Created by vgangwar7 on 31/05/16. 
public class ForecastFragment extends Fragment { 
public final class BuildConfig { 
    public static final String OPEN_WEATHER_MAP_API_KEY = "1912b14c788b31e4f1ae441a0ceefb18"; 
} 

private ArrayAdapter<String> forecastAdapter; 
public ForecastFragment(){} 

public void onCreate(Bundle savedInstanceState){ 
    super.onCreate(savedInstanceState); 
    // Add this line in order for this fragment to handle menu events 
    setHasOptionsMenu(true); 
    updateWeather(); 
} 

public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
    // Inflate the menu; this adds items to the action bar if it is present. 
    inflater.inflate(R.menu.forecastfragment, menu); 
} 

public boolean onOptionsItemSelected(MenuItem menuItem) { 
    int id = menuItem.getItemId(); 

    if (id == R.id.action_refresh) { 
     FetchWeatherTask weatherTask = new FetchWeatherTask(); 
     weatherTask.execute("110085"); 
     return true; 
    } 

    return super.onOptionsItemSelected(menuItem); 
} 

private void updateWeather() { 
    FetchWeatherTask weatherTask = new FetchWeatherTask(); 
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); 
    String location = preferences.getString(getString(R.string.pref_location_key), 
      getString(R.string.pref_location_default)); 
    weatherTask.execute(location); 
} 

public void onStart() { 
    super.onStart(); 
    updateWeather(); 
} 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
         Bundle savedInstanceState) { 
    // Inflate the layout for this fragment 
    String[] forecastArray = 
      {"Today - Sunny - 88/63", 
      "Tomorrow - Foggy - 70/40", 
      "Weds - Cloudy - 72/63", 
      "Thurs - Asteroids - 75/65", 
      "Fri - Heavy Rain - 65/56", 
      "Sat - HELP TRAPPED IN WEATHERSITUATION - 65/51", 
      "Sun - Sunny - 88/68"}; 

    List<String> weekForecast = new ArrayList<String>(Arrays.asList(forecastArray)); 

    forecastAdapter = new ArrayAdapter<>(getActivity(),R.layout.list_item_forecast, R.id.list_item_forecast_textview, weekForecast); 
    View rootView = inflater.inflate(R.layout.fragment_main, container, false); 
    ListView listView = (ListView) rootView.findViewById(R.id.listview_forecast); 
    listView.setAdapter(forecastAdapter); 
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 
     @Override 
     public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { 
      Toast.makeText(getActivity(), forecastAdapter.getItem(position), Toast.LENGTH_SHORT).show(); 
     } 
    }); 
    return rootView; 
} 

public class FetchWeatherTask extends AsyncTask<String, Void, String[]> { 

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

    String format = "json"; 
    String units = "metric"; 
    final int numDays = 7; 

    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. 
     SimpleDateFormat shortenedDateFormat = new SimpleDateFormat("EEE MMM dd"); 
     return shortenedDateFormat.format(time); 
    } 
    /** 
    * 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. 
    */ 
    //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_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); 

      //create a Gregorian Calendar, which is in current date 
      GregorianCalendar gc = new GregorianCalendar(); 
      //add i dates to current date of calendar 
      gc.add(GregorianCalendar.DATE, i); 
      //get that date, format it, and "save" it on variable day 
      Date time = gc.getTime(); 
      SimpleDateFormat shortenedDateFormat = new SimpleDateFormat("EEE MMM dd"); 
      day = shortenedDateFormat.format(time); 

      // 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("FetchWeatherTask", "Forecast entry: " + s); 
     } 
     return resultStrs; 

    } 

    @Override 
    protected String[] doInBackground(String... params) { 

     if (params.length == 0) { 
      return null; 
     } 

     //These two needed to be declared outside try catch block 
     HttpURLConnection urlConnection = null; 
     BufferedReader reader = null; 

     String forecastJsonStr = null; 

      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"; 
       final String APPID_PARAM = "APPID"; 

       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)) 
         .appendQueryParameter(APPID_PARAM, BuildConfig.OPEN_WEATHER_MAP_API_KEY) 
         .build(); 

       URL url = new URL(builtUri.toString()); 

       Log.v(TAG, "Built URI " + builtUri.toString()); 

       // Create the request to OpenWeatherMap, and open the connection 
       urlConnection = (HttpURLConnection) url.openConnection(); 

       // 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. 
        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("ForecastFragment", "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) { 
        urlConnection.disconnect(); 
       } 
       if (reader != null) { 
        try { 
         reader.close(); 
        } catch (final IOException e) { 
         Log.e("ForecastFragment", "Error closing stream", e); 
        } 
       } 
      } 
     try{ 
      getWeatherDataFromJson(forecastJsonStr, numDays); 
     }catch (JSONException e){ 
      Log.e(TAG ,e.getMessage(), e); 
      e.printStackTrace(); 
     } 

     return null; 

    } 

    @Override 
    public void onPostExecute(String[] result) { 
     if (result != null) { 
      forecastAdapter.clear(); 
      for (String dayForecastStr : result) { 
       forecastAdapter.addAll(dayForecastStr); 
      } 
      forecastAdapter.notifyDataSetChanged(); 
     } 
    } 

} 
} 

MainActivity.java

public class MainActivity extends AppCompatActivity 
{ 

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    if (savedInstanceState == null) { 


    getSupportFragmentManager().beginTransaction().add(R.id.container, new ForecastFragment()).commit(); 
    } 

} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    // Inflate the menu; this adds items to the action bar if it is present. 
    getMenuInflater().inflate(R.menu.main, menu); 

    return true; 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    // Handle action bar item clicks here. The action bar will 
    // automatically handle clicks on the Home/Up button, so long 
    // as you specify a parent activity in AndroidManifest.xml. 
    int id = item.getItemId(); 

    //noinspection SimplifiableIfStatement 
    if (id == R.id.action_settings) { 
     return true; 
    } 
    if (id == R.id.action_refresh) { 
     return true; 
    } 

    return super.onOptionsItemSelected(item); 
} 
} 

Хотя, в моем LogCat, я могу видеть неправдоподобные данные из API и не существует какой-либо ошибки в коде. LogCat -

06-04 16: 11: 31,432 3730-3769/com.example.vgangwar7.sunshine В/FetchWeatherTask: запись Прогноз: Вс июн 05 - Очистить - 43/31 06-04 16:11: 31.432 3730-3769/com.example.vgangwar7.sunshine V/FetchWeatherTask: запись о прогнозе: пн июн 06 - очистить - 40/26 06-04 16: 11: 31.432 3730-3769/com.example.vgangwar7.sunshine V/FetchWeatherTask: Запись прогноза: Вт июн 07 - Очистить - 39/28 06-04 16: 11: 31.432 3730-3769/com.example.vgangwar7.sunshine V/FetchWeatherTask: запись о прогнозе: ср. Июнь 08 - очистить - 39/26 06-04 16: 11: 31.432 3730-3769/com.example.vgangwar7.sunshine V/FetchWeatherTask: Запись прогноза: Чт июн 09 - Очистить - 41/27 06-04 16: 11: 31.432 3730-3769/com .example.vgangwar7.sunshine V/FetchWeatherTask: запись Прогноз: Пт Июн 10 - Дождь - 39/26

+0

Я считаю Выборку данных погоды асинхронная задача , Возможно ли, что вы загружаете макет до того, как задача действительно завершена? Можно ли вызвать .get() при выполнении? если это так, сделайте это, чтобы убедиться, что оно завершено до перехода к следующему исполнению. Например: weatherTask.execute ("110085"). get(); – Jimmy

+0

Что вы на самом деле хотите увидеть в приложении? В вашем вопросе говорится, что данные не обновляются после обновления. Как бы то ни было, в вашем doInBackground-Method вы просто ежедневно читаете данные о погоде в течение следующих 7 дней - так что изменений в любом случае не будет (за исключением того, что вы обновите приложение на следующий день). – Christian

+0

@Jimmy Поддельные данные, которые я использовал, будут отображаться первыми. Таким образом, после нажатия кнопки обновления кнопка переходит в onOptionsItemSelected, где он извлекает новую AsyncTask P.S - Я добавил logcat –

ответ

0

попробовать Процентовка OnStart метод:

@Override 
public void onStart(){ 
    super.onStart(); 
    updateWeather(); 
} 

С уважением.

+0

Извините, сэр Ничего не случилось даже после этого. –

0

Когда вы выполняете асинхронную задачу, вам нужно убедиться, что задача выполнена до использования результата, полученного этой задачей. В вашем случае, когда выбрано обновление, вы выполняете задачу с weatherTask.execute("110085");. Допустим, для выполнения задачи требуется 3 секунды и вернуть результат. но ваш оператор return в следующей строке будет выполнен сразу же, заставляя макет перезагружать (скажем, для перезагрузки требуется 1 секунда). Что происходит здесь, когда вы выполняете асинхронную задачу, будет создан другой процесс для извлечения данных, и первоначальное выполнение будет продолжено немедленно, не дожидаясь завершения задачи async. Если выполнение немедленно переходит к следующей строке, не дожидаясь результата из вашей задачи. В вашем случае перезагрузка выполняется до того, как ваша задача действительно вытащила данные. Например, ваш экран загружает первую секунду ввода метода SelectSelected, но только через 2 секунды вы получаете данные о погоде из задачи async. Таким образом, обновленные данные отображаются в logcat, но не на экране, так как активность не получала данные во время загрузки. Поэтому вам нужно убедиться, что вы загружаете свой макет только после получения ваших данных. вы можете сделать это, вызвав get() при выполнении.

В методе onOptionsItemSelected из ForecastFragment, изменить

weatherTask.execute("110085");

к

weatherTask.execute("110085").get();

Это должно сделать магию для вас.

+0

Я пробовал этот метод, но все еще нет никаких изменений @Jimmy :( –

+0

Большое спасибо, но я понял ошибку. –

+0

@VivekGangwar Пожалуйста, разместите свое решение и отметьте его как ответ, чтобы другие могли ссылаться на него, если они – Jimmy

0

Я не уверен, когда вы хотите «обновить» данные и как вы это делаете, можете ли вы объяснить только свою стратегию обновления данных вместо копирования всего вашего кода? Обычно шаги:

  1. выполнить HTTP запрос в другом потоке
  2. когда запрос готов передать ответ на основной поток
  3. в главном потоке обновления пользовательского интерфейса с данными (это зависит от того, элементы управления вы используете в вашем приложении , чтобы показать данные.

Я полагаю, вы читали о состояниях активности в Android. Если вы не сделали, сделайте это. Тогда вы будете иметь возможность использовать OnStart или onResume в зависимости от ваших потребностей.

+0

В настоящее время я изучаю андроид из udacity. Да, вы правы, я использовал эти шаги при разработке приложения. Даже если я удалю функцию onStart из кода, изменений не будет. –

0

Вызовите updateWeather(); функции в методе OnOptionsItemSelected()

public boolean onOptionsItemSelected(MenuItem menuItem) { 
int id = menuItem.getItemId(); 

    if (id == R.id.action_refresh) { 
     //FetchWeatherTask weatherTask = new FetchWeatherTask(); 
     //weatherTask.execute("110085"); 
     updateWeather(); 
     return true; 
    } 

    return super.onOptionsItemSelected(menuItem); 
} 

В вашей doInBackground добавить оператор возврата, когда вы делаете прогноз погоды строку из forecastJsonStr

@Override 
protected String[] doInBackground(String... params) { 
    .//your code 
    .//your code 
    .//your code 
    . 
    . 
    try{ 
     return getWeatherDataFromJson(forecastJsonStr, numDays);//add return here!! 
    }catch (JSONException e){ 
     Log.e(TAG ,e.getMessage(), e); 
     e.printStackTrace(); 
    } 

    return null; 
} 
+0

Я уже пробовал это ничего не случилось! @muddasir –

+0

Я обновил свой ответ, пожалуйста, просмотрите обновленный. –

Смежные вопросы