2016-04-15 61 views
0

我一直在學習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> 

我完全新的應用程序開發,我知道可能有很多愚蠢的錯誤。但我甚至不知道如何正確調試。你會給我一些建議。非常感謝所有幫助!

回答

0

在主要活動

變化的onCreate()

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

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

非常感謝您的及時答覆!是的,它的工作,但我的項目進一步的錯誤警告。你可以看看適配器類文件嗎? logcat說'NullpointerException:嘗試寫入'空對象引用'字段'android.widget.TextView RowAdapter $ ViewHolder.textView1'。 – Emile

+0

在適配器類中的if(convertView == null){}中添加holder = new Holder()。 –

+0

哦,非常感謝你!得到了我想要的結果。似乎與我在主要活動文件中發生的錯誤類似:P – Emile

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); 
     } 
    } 
} 
} 
0

錯誤:

呦您已在申報部分聲明private RowAdapter rowAdapter;

雖然再次您已聲明並初始化

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

所以將其更改爲

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

只是聲明ArrayList<Weather> data = new ArrayList<Weather>();以外的方法,改變onPostExecute方法

@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); 
      } 
     } 

希望你的問題解決了。

+0

我想我已經在主要活動文件的開頭聲明瞭它。你的意思是我應該在PostExecute方法或其他地方宣佈它嗎? – Emile

+0

是的,因爲您在主活動開始時沒有ArrayList 數據值。所以你必須聲明onPostExecute方法。 –

0

刪除適配器的本地聲明,因爲您已經在全局聲明它。

rowAdapter = new RowAdapter(MainActivity.this, R.layout.weather_item, data); 
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方法中多了一個局部變量。

Happy_Coding;

相關問題