我已经学习了两个星期的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>
我对应用程序开发完全不熟悉,我知道可能会有许多愚蠢的错误。但我甚至不知道如何正确调试。你能给我一些建议真是太好了。非常感谢所有帮助!
答案 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
方法中创建另一个具有相同名称的本地变量。