Android:CustomAdapter ArrayList数据Nullpointerexception

时间:2016-04-15 04:38:41

标签: android json listview nullpointerexception adapter

我已经学习了两个星期的Android应用程序开发,并且真的被困在这里。我试图从ArrayList中的OpenWeatherMap API检索每小时预测数据(采用JSON格式),该数据可以通过自定义适配器安装到具有三个元素的Listview中。如果用户输入城市名称,他/她应该能够看到列表 - 每小时的天气信息占据列表的一行。数据检索过程由AsyncTask完成。

然而,在击中"找到太阳"按钮,应用程序崩溃,logcat一直显示我:

>FATAL EXCEPTION: main
>java.lang.NullPointerException: Attempt to invoke virtual method 'RowAdapter.clear()' on a null object reference
>at MainActivity$WeatherDownloadTask.onPostExecute(MainActivity.java:78)
>at MainActivity$WeatherDownloadTask.onPostExecute(MainActivity.java:61)
>at android.os.AsyncTask.finish(AsyncTask.java:636)
>at android.os.AsyncTask.access$500(AsyncTask.java:177)
>at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653)
>at android.os.Handler.dispatchMessage(Handler.java:102)
>at android.os.Looper.loop(Looper.java:135)
>at android.app.ActivityThread.main(ActivityThread.java:5254)
>at java.lang.reflect.Method.invoke(Native Method)
>at java.lang.reflect.Method.invoke(Method.java:372)
>at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
>at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

Line 61 is    public class WeatherDownloadTask extends AsyncTask<String, Void, ArrayList<Weather>> "\n"
Line 78 is    for (Weather w : weather) {rowAdapter.add(w);}

这是我的主要活动java文件:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private RowAdapter rowAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ArrayList<Weather> data = new ArrayList<Weather>();
    ListView listv = (ListView) findViewById(R.id.listv);
    RowAdapter rowAdapter = new RowAdapter(MainActivity.this, R.layout.weather_item, data);
    listv.setAdapter(rowAdapter);
}

public void handleClick(View v) {
    Log.v(TAG, "Search Button handled");
    EditText text = (EditText) findViewById(R.id.cityname);
    String searchTerm = text.getText().toString();

    WeatherDownloadTask task = new WeatherDownloadTask();
    task.execute(searchTerm);
}

public class WeatherDownloadTask extends AsyncTask<String, Void, ArrayList<Weather>> {

    @Override
    protected ArrayList<Weather> doInBackground(String... params) {
        try {
            ArrayList<Weather> data = WeatherDownloader.downloadWeather(params[0]);
            Log.d(TAG, data.toString());
            return data;
        } catch (JSONException e) {
            return null;
        }
    }

    @Override
    protected void onPostExecute(ArrayList<Weather> weather) {
            super.onPostExecute(weather);
            rowAdapter.clear();
            for (Weather w : weather) {
                rowAdapter.add(w);
            }
        }
    }
}

这是从API下载数据的代码:

public class WeatherDownloader {
private static String BASE_URL = "http://api.openweathermap.org/data/2.5/weather?q=";
private static String IMG_URL = "http://openweathermap.org/img/w/";

// returns ArrayList of Weather, rather than String[]
public static ArrayList<Weather> downloadWeather(String location) throws JSONException {
    HttpURLConnection con = null;
    ArrayList<Weather> weather = null;
    BufferedReader reader = null;

    try {
        con = (HttpURLConnection) (new URL(BASE_URL + location + "&units=metric" +
                "&APPID=" + BuildConfig.OPEN_WEATHER_MAP_API_KEY)).openConnection();
        con.setRequestMethod("GET");
        con.setDoInput(true);
        con.setDoOutput(true);
        con.connect();

        StringBuffer buffer = new StringBuffer();
        InputStream inputStream = con.getInputStream();
        if (inputStream == null) return null;
        reader = new BufferedReader(new InputStreamReader(inputStream));

        String line = reader.readLine();
        while (line != null) {
            buffer.append(line + "\n");
            line = reader.readLine();
        }

        if (buffer.length() == 0) {
            return null;
        }
        String results = buffer.toString();

        weather = parseWeatherJSON(results);
        if (weather == null) weather = new ArrayList<Weather>();
    } catch (IOException e) {
        return null;
    } finally {
        if (con != null) {
            con.disconnect();
        }
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
            }
        }
    }
    return weather;
}


/**
 * Parses a JSON String into a list of Weather objects
 */
public static ArrayList<Weather> parseWeatherJSON(String json) throws JSONException {
    ArrayList<Weather> weather = new ArrayList<Weather>();
    JSONObject jsonObject = new JSONObject(json);
    Weather item = new Weather();

    JSONArray JSONArray_weather = jsonObject.getJSONArray("weather");

    for (int i = 0; i < JSONArray_weather.length(); i++) {
        JSONObject JSONObject_weather = JSONArray_weather.getJSONObject(i);
        item.setSun(JSONObject_weather.getString("main"));// get the weather description

        DateFormat df = DateFormat.getDateTimeInstance();
        String timestr = df.format(new Date(jsonObject.getLong("dt") * 1000));
        item.setTime(timestr); // get the time;

        // key = "main"
        JSONObject JSONObject_main = jsonObject.getJSONObject("main");
        item.setTemperature(JSONObject_main.getDouble("temp")); // get the temperature;

        weather.add(item);
        }
    return weather;
    }
}

这是Adapter类:

public class   RowAdapter extends ArrayAdapter<Weather> {

private final Context context;
private final ArrayList<Weather> data;
private final int resource;

// a constructor
public RowAdapter(Context context, int resource, ArrayList<Weather> data) {
    super(context, resource, data);
    this.context = context;
    this.data = data;
    this.resource = resource;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View row;
    row = convertView;
    ViewHolder holder = null;

    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        row = inflater.inflate(R.layout.weather_item,parent,false);

    // initialize the components

        holder.textView1 = (TextView)row.findViewById(R.id.sun);
        holder.textView2 = (TextView) row.findViewById(R.id.time);
        holder.textView3 = (TextView) row.findViewById(R.id.temp);
        row.setTag(holder);
    }
    else {
        holder = (ViewHolder)row.getTag();
    }

    Weather weather = data.get(position);

    holder.textView1.setText(weather.getSun());
    holder.textView2.setText(weather.getTime());
    holder.textView3.setText(String.valueOf(weather.getTemperature()));
    return row;
}
static class ViewHolder
{
    TextView textView1;
    TextView textView2;
    TextView textView3;
}
}

主要活动xml文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/mainactivity"
    android:padding="16dp"
    android:orientation="vertical"
    tools:context=".MainActivity"
    android:weightSum="1">

<EditText
    android:id="@+id/cityname"
    android:layout_width="214dp"
    android:layout_height="wrap_content"
    android:drawableLeft="@android:drawable/ic_menu_search"
    android:inputType="text"
    android:imeOptions="actionDone"
    android:hint="City..."
    android:layout_alignParentTop="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true" />

<Button
    android:id="@+id/searchbtn"
    android:layout_width="wrap_content"
    android:layout_height="50dp"
    android:text="Find Sun"
    android:textAllCaps="false"
    android:layout_gravity="right"
    android:layout_alignParentTop="true"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:onClick="handleClick"/>

<TextView
    android:id="@+id/sunornot"
    android:layout_width="171dp"
    android:layout_height="70dp"
    android:text = "Will there be sun?"
    android:textSize="20dp"
    android:layout_gravity="right"
    android:layout_weight="0.22"
    android:layout_below="@+id/cityname"
    android:layout_alignParentRight="true"
    android:layout_marginLeft="30dp"
    android:layout_marginTop="20dp"
    android:layout_alignParentEnd="true"
    android:layout_toRightOf="@+id/weather_icon"
    android:layout_toEndOf="@+id/weather_icon" />

<ImageView
    android:id="@+id/weather_icon"
    android:layout_width="65dp"
    android:layout_height="65dp"
    android:layout_above="@+id/listv"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true" />

<ListView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/listv"
    android:layout_alignParentBottom="true"
    android:layout_below="@+id/sunornot" />

</RelativeLayout>

我对应用程序开发完全不熟悉,我知道可能会有许多愚蠢的错误。但我甚至不知道如何正确调试。你能给我一些建议真是太好了。非常感谢所有帮助!

6 个答案:

答案 0 :(得分:1)

在方法之外声明#include <stdio.h> #include "stackoverflow.h" int main() { printf("my_var = %d\n", my_var); return 0; } 并更改ArrayList<Weather> data = new ArrayList<Weather>();方法

onPostExecute

希望你的问题得到解决。

答案 1 :(得分:0)

这是你的问题

RowAdapter rowAdapter = new RowAdapter(MainActivity.this, R.layout.weather_item, data); 

您必须将 RowAdapter 移至

rowAdapter = new RowAdapter(MainActivity.this, R.layout.weather_item, data); 

试试这个!!!!

public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private RowAdapter rowAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

ArrayList<Weather> data = new ArrayList<Weather>();
ListView listv = (ListView) findViewById(R.id.listv);
rowAdapter = new RowAdapter(MainActivity.this, R.layout.weather_item, data);
listv.setAdapter(rowAdapter);
}

public void handleClick(View v) {
Log.v(TAG, "Search Button handled");
EditText text = (EditText) findViewById(R.id.cityname);
String searchTerm = text.getText().toString();

WeatherDownloadTask task = new WeatherDownloadTask();
task.execute(searchTerm);
}

public class WeatherDownloadTask extends AsyncTask<String, Void, ArrayList<Weather>> {

@Override
protected ArrayList<Weather> doInBackground(String... params) {
    try {
        ArrayList<Weather> data = WeatherDownloader.downloadWeather(params[0]);
        Log.d(TAG, data.toString());
        return data;
    } catch (JSONException e) {
        return null;
    }
}

@Override
protected void onPostExecute(ArrayList<Weather> weather) {
        super.onPostExecute(weather);
        rowAdapter.clear();
        for (Weather w : weather) {
            rowAdapter.add(w);
        }
    }
}
}

答案 2 :(得分:0)

在主要活动的onCreate()

变化

RowAdapter rowAdapter = new RowAdapter(MainActivity.this, R.layout.weather_item, data);

rowAdapter = new RowAdapter(MainActivity.this, R.layout.weather_item, data);

答案 3 :(得分:0)

错误:

您已在声明部分声明extern int g_foo;

虽然你又宣布并初始化了

private RowAdapter rowAdapter;

所以将其改为

RowAdapter rowAdapter = new RowAdapter(MainActivity.this, R.layout.weather_item, data);
listv.setAdapter(rowAdapter);

答案 4 :(得分:0)

删除适配器的本地声明,因为您已经全局声明它。

 @Override
 protected void onPostExecute(ArrayList<Weather> weather) {
                super.onPostExecute(weather);
                data.clear();

                for (Weather w : weather) {
                    data.add(w);
                }
              RowAdapter rowAdapter = new RowAdapter(MainActivity.this, R.layout.weather_item, data);
             listv.setAdapter(rowAdapter);
            }
        }

答案 5 :(得分:0)

错误在于声明和初始化rowAdapter,替换下面的行

 RowAdapter rowAdapter = new RowAdapter(MainActivity.this, R.layout.weather_item, data);

rowAdapter = new RowAdapter(MainActivity.this, R.layout.weather_item, data);

为什么:因为rowAdapter是一个全局变量,您从未初始化并在onCreate方法中创建另一个具有相同名称的本地变量。