在onpostexecute方法中捕获mforecastadapter的java.lang.NullPointerException

时间:2016-03-25 10:01:06

标签: android

我在MainActivityFragment中初始化了数组适配器,我用虚假数据初始化了适配器,然后尝试通过从服务器获取数据来更新适配器。在mforecastadapter方法中使用onPostExecute()获取空指针异常,该方法是内联类FetchWeatherTask的成员方法。

package com.example.puneet.sunshine;

import android.os.AsyncTask;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.util.Log;

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

import android.text.format.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
/**
 * A placeholder fragment containing a simple view.
 */
public class MainActivityFragment extends Fragment {
public ArrayAdapter<String> mforecastadapter;
public MainActivityFragment() {

}


public View onCreateView(LayoutInflater inflater, ViewGroup container,             Bundle savedInstanceState) {

    View rootview = inflater.inflate(R.layout.fragment_main,container,true);
        String[] forecast = {
                "Today - Sunny - 80/66",
                "Tomorrow - Cloudy - 75/55",
                "Weds - Foggy - 86/65",
                "Thurs - Asteroids - 76/43",
                "Fri - Sunny - 87/56",
                "Sat - Foggy - 76/55",
                "Sun - Cloudy - 66/44"
        };
        ArrayList<String> weekforecast = new ArrayList<String>(Arrays.asList(forecast));
        mforecastadapter = new ArrayAdapter<String>(getActivity(), R.layout.list_forecast_layout, R.id.list_item_forecast_textview, weekforecast);

        ListView l = (ListView) rootview.findViewById(R.id.listView_forecast);
        l.setAdapter(mforecastadapter);

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

    /**
     * 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);

        // OWM returns daily forecasts based upon the local time of the city that is being
        // asked for, which means that we need to know the GMT offset to translate this data
        // properly.

        // Since this data is also sent in-order and the first day is always the
        // current day, we're going to take advantage of that to get a nice
        // normalized UTC date for all of our weather.

        Time dayTime = new Time();
        dayTime.setToNow();

        // we start at the day returned by local time. Otherwise this is a mess.
        int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff);

        // now we work exclusively in UTC
        dayTime = new Time();
        int le = weatherArray.length();
        String str = new String(String.valueOf(le));
        Log.v(LOG_TAG,str);

        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;
            // Cheating to convert this to UTC time, which is what we want anyhow
            dateTime = dayTime.setJulianDay(julianStartDay+i);
            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

    public 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;

         if (params.length == 0) {
             return null;
         }
         // Will contain the raw JSON response as a string.
         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
             String place = params[0];
             String mode = "json";
             String unit = "metric";
             String count = "7";
             String baseUrl = "http://api.openweathermap.org/data/2.5/forecast/daily?q="+place+"&mode=json&units=metric&cnt=7";
             String apiKey = "&APPID=" + BuildConfig.OPEN_WEATHER_MAP_API_KEY;
             URL url = new URL(baseUrl.concat(apiKey));
             String o1 = new String(String.valueOf(url));
             Log.v(LOG_TAG,"url="+o1);

             // 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.
                 Log.v(LOG_TAG,"empty input stream");
                 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.
                 Log.v(LOG_TAG,"empty buffer");
                 return null;
             }
             forecastJsonStr = buffer.toString();

             Log.v(LOG_TAG, "Forecast Json 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 attemping
             // 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, 7);
         } catch (JSONException e) {
             Log.v(LOG_TAG,"null object");
             Log.e(LOG_TAG, e.getMessage(), e);
             e.printStackTrace();
         }
         return null;
     }

    @Override
    protected void onPostExecute(String[] result) {

        super.onPostExecute(result);
        if(mforecastadapter==null){
            Log.v(LOG_TAG,"adapter null");
        }
        if(result!=null){
            mforecastadapter.clear();
            for(String s: result){
                mforecastadapter.add(s);
            }
        }
        mforecastadapter.notifyDataSetChanged();
    }
}

}

1 个答案:

答案 0 :(得分:0)

setAdapter代码下运行您的任务,如下所示:

ListView l = (ListView) rootview.findViewById(R.id.listView_forecast);
 l.setAdapter(mforecastadapter);
 new FetchWeatherTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,inputString);

或者您可以初始化mforecastAdapter

if(mforecastadapter==null){
          Log.v(LOG_TAG,"adapter null");
          mforecastadapter = new ArrayAdapter<String>(getActivity(), R.layout.list_forecast_layout, R.id.list_item_forecast_textview, weekforecast);
}

并确保在ListView上设置此适配器。

我推荐第一个解决方案