我一直在學習Android應用程序開發兩週,真的陷入了困境。我嘗試從ArrayList中的OpenWeatherMap API檢索每小時預測數據(採用JSON格式),該數據可以通過自定義的適配器與三個元素配合到一個Listview中。如果用戶輸入城市名稱,他/她應該能夠看到一個列表 - 每小時的天氣信息佔據列表的一行。數據檢索過程由AsyncTask完成。Android:CustomAdapter ArrayList數據Nullpointerexception
然而擊中了「發現太陽」按鈕後,應用程序崩潰和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;
}
}
這是適配器類:
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>
我完全新的應用程序開發,我知道可能有很多愚蠢的錯誤。但我甚至不知道如何正確調試。你會給我一些建議。非常感謝所有幫助!
非常感謝您的及時答覆!是的,它的工作,但我的項目進一步的錯誤警告。你可以看看適配器類文件嗎? logcat說'NullpointerException:嘗試寫入'空對象引用'字段'android.widget.TextView RowAdapter $ ViewHolder.textView1'。 – Emile
在適配器類中的if(convertView == null){}中添加holder = new Holder()。 –
哦,非常感謝你!得到了我想要的結果。似乎與我在主要活動文件中發生的錯誤類似:P – Emile