2016-05-20 110 views
0

我不久前就开始学习android。它只是在某种程度上这个错误在我后来一直困扰着我。我正在按照教程构建一个名为Sunshine的天气应用程序。我已经仔细检查了API,它看起来不错。我也继承了AsyncTask类来处理后台线程,重写了doInBackground()和onPostExecute()方法成功返回到我的UI线程(我想)。我检查了我的代码很多次,但无法解决错误。致命异常:AsyncTask#1由:java.lang.NullPointerException导致

05-20 01:10:04.036 28055-28154/com.example.android.sunshine E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1 
                      Process: com.example.android.sunshine, PID: 28055 
                      java.lang.RuntimeException: An error occured while executing doInBackground() 
                       at android.os.AsyncTask$3.done(AsyncTask.java:300) 
                       at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355) 
                       at java.util.concurrent.FutureTask.setException(FutureTask.java:222) 
                       at java.util.concurrent.FutureTask.run(FutureTask.java:242) 
                       at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 
                       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
                       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
                       at java.lang.Thread.run(Thread.java:841) 
                      Caused by: java.lang.NullPointerException 
                       at org.json.JSONTokener.nextCleanInternal(JSONTokener.java:116) 
                       at org.json.JSONTokener.nextValue(JSONTokener.java:94) 
                       at org.json.JSONObject.<init>(JSONObject.java:155) 
                       at org.json.JSONObject.<init>(JSONObject.java:172) 
                       at com.example.android.sunshine.ForecastFragment$FetchWeatherTask.getWeatherDataFromJson(ForecastFragment.java:115) 
                       at com.example.android.sunshine.ForecastFragment$FetchWeatherTask.doInBackground(ForecastFragment.java:221) 
                       at com.example.android.sunshine.ForecastFragment$FetchWeatherTask.doInBackground(ForecastFragment.java:89) 
                       at android.os.AsyncTask$2.call(AsyncTask.java:288) 
                       at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
                       at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)  
                       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)  
                       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)  
                       at java.lang.Thread.run(Thread.java:841)  
05-20 01:10:04.826 28055-28055/com.example.android.sunshine D/AbsListView: onDetachedFromWindow 
D/AbsListView: onDetachedFromWindow05-20 01:15:04.106 28055-28154/com.example.android.sunshine I/Process: Sending signal. PID: 28055 SIG: 9 

forecastfragment文件

public class ForecastFragment extends Fragment { 
     private ArrayAdapter<String> mForecastAdapter; 
     public ForecastFragment() { 
     } 

     public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      setHasOptionsMenu(true); 
     } 

     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 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_refresh) { 
       FetchWeatherTask weatherTask = new FetchWeatherTask(); 
       weatherTask.execute("110025"); 
       return true; 
      } 

      return super.onOptionsItemSelected(item); 
     } 


     @Override 
     public View onCreateView(LayoutInflater inflater, ViewGroup container, 
           Bundle savedInstanceState) { 
      String[] data = { 
        "today-sunny - 41/29", 
        "today-sunny - 41/29", 
        "today-sunny - 41/29", 
        "today-sunny - 41/29", 
        "today-sunny - 41/29", 
        "today-sunny - 41/29", 
        "today-sunny - 41/29", 
      }; 
      List<String> weekForecast = new ArrayList<>(
        Arrays.asList(data)); 

      mForecastAdapter = 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(mForecastAdapter); 

      return rootView; 
     } 

     public class FetchWeatherTask extends AsyncTask<String, Void, String[]> { 
      private final String LOG_TAG = FetchWeatherTask.class.getSimpleName(); 

      public String getReadableDateString(long time) { 
       Date date = new Date(time * 1000); 
       SimpleDateFormat format = new SimpleDateFormat("E, MMM d"); 
       return format.format(date).toString(); 
      } 

    private String formatHighLows(double high, double low) { 
     long roundedHigh = Math.round(high); 
     long roundedLow = Math.round(low); 

     String highLowStr = roundedHigh + "/" + roundedLow; 
     return highLowStr; 
    } 

    private String[] getWeatherDataFromJson(String forecastJsonStr, int days) throws JSONException { 
     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[days]; 
     for (int i = 0; i < weatherArray.length(); i++) { 
      String day; 
      String description; 
      String highAndLow; 

      JSONObject dayForecast = weatherArray.getJSONObject(i); 

      long dateTime = dayForecast.getLong(OWM_DATETIME); 
      day = getReadableDateString(dateTime); 
      JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0); 
      description = weatherObject.getString(OWM_DESCRIPTION); 

      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) { 
     // These two need to be declared outside the try/catch 
// so that they can be closed in the finally block. 
     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 days = 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?&APPID=bab4c81d2c0f80d573a3c37211c3353e"; 
      final String QUERY_PARAM = "q"; 
      final String FORMAT_PARAM = "mode"; 
      final String UNITS_PARAM = "units"; 
      final String DAYS_PARAM = "cnt"; 
      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(days)) 
        .build(); 
      URL url = new URL(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; 
      } 
      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 JSON string:" + forecastJsonStr); 
     } catch (IOException e) { 
      Log.e("PlaceholderFragment", "Error ", e); 
      // If the code didn't successfully get the weather data, there's no point in attemping 
      // to parse it. 
      forecastJsonStr = null; 
     } finally { 
      if (urlConnection != null) { 
       urlConnection.disconnect(); 
      } 
      if (reader != null) { 
       try { 
        reader.close(); 
       } catch (final IOException e) { 
        Log.e("PlaceholderFragment", "Error closing stream", e); 
       } 
      } 
     } 
     try { 
      return getWeatherDataFromJson(forecastJsonStr, days); 
     } catch (JSONException e) { 
      Log.e(LOG_TAG, e.getMessage(), e); 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    @Override 
    protected void onPostExecute(String[] result) { 
     if (result != null){ 
      mForecastAdapter.clear(); 
      for (String dayForecastStr : result){ 
       mForecastAdapter.add(dayForecastStr); 
      } 
     } 
    } 
} 
} 

我在这一个小白,它已经2天,我仍然无法追查问题。所有的帮助表示赞赏。提前致谢。

+0

你来过[这个答案](http://stackoverflow.com/a/14180721/2437227)? – ThomasV

+0

在doInBackground中您的'forecastJsonStr'为null。所以,当你调用getWeatherDataFromJson与空值它抛出一个异常 –

+0

我调用了你的URL。您的API密钥错误。 这是我收到的回复 '{“cod”:401,“message”:“无效的API密钥,请参阅http://openweathermap.org/faq#error401获取更多信息。”} –

回答

0

你得到了正确的答案forecastJsonStr?也许它是空的;

我试图访问的URL,它的响应就像this

什么是你Log.v(LOG_TAG, "Forecast JSON string:" + forecastJsonStr);输出?

0

早些时候我的代码是这样的

String format = "json"; 
     String units = "metric"; 
     int days = 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?&APPID=bab4c81d2c0f80d573a3c37211c3353e"; 
      final String QUERY_PARAM = "q"; 
      final String FORMAT_PARAM = "mode"; 
      final String UNITS_PARAM = "units"; 
      final String DAYS_PARAM = "cnt"; 
      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(days)) 
        .build(); 

此外,我已经声明了一个string q = "110025",因为它没有任何地方初始化之前,我通过它的.appendQueryParameter(QUERY_PARAM,q)参数这样,瞧,itworked。 现在的代码看起来像

String format = "json"; 
     String units = "metric"; 
     q="110025"; 
     int days = 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?&APPID=bab4c81d2c0f80d573a3c37211c3353e"; 
      final String QUERY_PARAM = "q"; 
      final String FORMAT_PARAM = "mode"; 
      final String UNITS_PARAM = "units"; 
      final String DAYS_PARAM = "cnt"; 
      Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon() 
        .appendQueryParameter(QUERY_PARAM, q) 
        .appendQueryParameter(FORMAT_PARAM, format) 
        .appendQueryParameter(UNITS_PARAM, units) 
        .appendQueryParameter(DAYS_PARAM, Integer.toString(days)) 
        .build(); 

我认为这个问题是在URL的形成只是其中q的值之前没有初始化,因为其中有一个空指针异常。