I have a ArrayAdapter which updates the ListView by fetching data from an API. API is working fine and I'm getting the data using an AsyncTask.
The OnPostExecute method should clear the ArrayAdapter and add new data to it.
But I'm facing some errors saying java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ArrayAdapter.clear()' on a null object reference
package com.example.sunshine;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.format.Time;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* {@link WeatherFragment.OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {@link WeatherFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class WeatherFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private ArrayAdapter<String> mAdapter;
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public EditText locationCity;
private OnFragmentInteractionListener mListener;
public WeatherFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment WeatherFragment.
*/
// TODO: Rename and change types and number of parameters
public static WeatherFragment newInstance(String param1, String param2) {
WeatherFragment fragment = new WeatherFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_weather, container, false);
String[] forecastArray = {"Mon 6/23 - Sunny - 31/17",
"Tue 6/24 - Foggy - 21/8",
"Wed 6/25 - Cloudy - 22/17",
"Thurs 6/26 - Rainy - 18/11",
"Fri 6/27 - Foggy - 21/10",
"Sat 6/28 - TRAPPED IN WEATHERSTATION - 23/18",
"Sun 6/29 - Sunny - 20/7"};
List<String> weekForecast = new ArrayList<>(Arrays.asList(forecastArray));
mAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, weekForecast );
mAdapter.notifyDataSetChanged();
ListView listView = (ListView) view.findViewById(R.id.listView1);
Log.d("Log", "If listview is null "+listView);
listView.setAdapter(mAdapter);
return view;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
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);
return roundedHigh + "/" + roundedLow;
}
/**
* 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();
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
protected String[] doInBackground(String... params) {
if(params.length == 0){
return null;
}
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String format = "json";
String units = "metric";
int numDays = 7;
String forecastJSONStr = null;
try {
final String 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 COUNT_PARAM = "cnt";
final String APPID_PARAM = "APPID";
Uri builtUri = Uri.parse(BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM, params[0])
.appendQueryParameter(FORMAT_PARAM, format)
.appendQueryParameter(UNITS_PARAM, units)
.appendQueryParameter(COUNT_PARAM, Integer.toString(numDays))
.appendQueryParameter(APPID_PARAM, BuildConfig.OWMAPIKey)
.build();
URL url = new URL(builtUri.toString());
Log.v(LOG_TAG, "Built Uri"+ builtUri.toString());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuilder buffer = new StringBuilder();
if(inputStream == null){
forecastJSONStr = null;
}
if(inputStream != null){
reader = new BufferedReader(new InputStreamReader(inputStream));
}
String line;
if(reader != null){
while((line = reader.readLine()) != null){
buffer.append(line).append('\n');
}
}
if(buffer.length() == 0){
forecastJSONStr = null;
}
forecastJSONStr = buffer.toString();
Log.e(LOG_TAG, "Forecast String " + forecastJSONStr);
} catch (ProtocolException | MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
Log.e(LOG_TAG, "onCreateView: Error", e);
forecastJSONStr = 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 {
if(forecastJSONStr != null){
Log.v(LOG_TAG, "doInBackground: "+forecastJSONStr);
String[] results= getWeatherDataFromJson(forecastJSONStr, numDays);
Log.v(LOG_TAG, "doInBackground: Check result" +Arrays.toString(results));
return results;
// return getWeatherDataFromJson(forecastJSONStr, numDays);
}
else{
Log.e(LOG_TAG, "Check your internet!" );
}
}catch (JSONException e){
Log.e(LOG_TAG, e.getMessage(), e);
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String[] result) {
Log.v(LOG_TAG, "onPostExecute: Check result object" + Arrays.toString(result));
Log.i(LOG_TAG, "onPostExecute: "+mAdapter);
mAdapter.clear();
mAdapter.addAll(result);
// if(result != null){
//// for(String dayForecastStr : result) {
//// mAdapter.add(dayForecastStr);
//// }
//
// }
// super.onPostExecute(result);
}
}
}
Check Line 351 for the exact line which is causing the problem.
Apologies if it's a noob question, but I am new to Android Development.
Adapterinon Post Executemethod. Transfer that fromon Create Viewtoon Post Execute.ArrayAdapterand show where you attempt to clear it. Code dumps and "Why doesn't this work?" are not good questions.ArrayAdapterhere . Tried to clear it here