在我的程序中,我正在尝试将天气状况列表更新为ListView。我将aSON下载并存储在asyncTask中,然后在onPostExecute和notifyDataSetChanged期间将数据解析到我的List中。我在这里看了几个相关的问题,但我不确定我错过了什么。这是我的MainActivity.java
public class MainActivity extends AppCompatActivity {
private List<Weather> weatherList = new ArrayList<>();
private WeatherArrayAdapter weatherArrayAdapter;
private ListView weatherListView;
private TextView locationEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
weatherListView = (ListView)findViewById(R.id.weatherListView);
weatherArrayAdapter = new WeatherArrayAdapter(this, weatherList);
weatherListView.setAdapter(weatherArrayAdapter);
locationEditText = (TextView)findViewById(R.id.locationEditText);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//Create a URL using the specific city entered by the user
URL url = createURL(locationEditText.getText().toString());
//As long as there is not a null url we get the weather
if(url!=null){
Log.e("URL", url.toString());
dismissKeyboard(locationEditText);
GetWeatherTask getLocalWeatherTask = new GetWeatherTask();
getLocalWeatherTask.execute(url);
}
else{
Snackbar.make(findViewById(R.id.coordinatorLayout),R.string.invalid_url, Snackbar.LENGTH_LONG).show();
}
}
});
}
private void dismissKeyboard(View v){
InputMethodManager inputMethodManager = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
private URL createURL(String city){
String apiKey = getString(R.string.api_key);
String baseURL = getString(R.string.web_service_url);
try{
String urlString = baseURL + URLEncoder.encode(city, "UTF-8") + "&units=imperial&cnt=16&APPID=" + apiKey;
return new URL(urlString);
}
catch (Exception e){
e.printStackTrace();
}
//Returns null only if the URL data was malformed
return null;
}
private class GetWeatherTask extends AsyncTask<URL, Void, JSONObject>{
@Override
protected JSONObject doInBackground(URL... params) {
HttpURLConnection connection = null;
try{
URL url = params[0];
Log.e("URL", url.toString());
connection = (HttpURLConnection)url.openConnection();
int responseCode = connection.getResponseCode();
if(responseCode == 200){
StringBuilder stringBuilder = new StringBuilder();
try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"))){
String line;
while((line = bufferedReader.readLine()) != null){
stringBuilder.append(line);
}
connection.disconnect();
return new JSONObject(stringBuilder.toString());
}
catch (Exception e){
e.printStackTrace();
}
}
else {
Snackbar.make(findViewById(R.id.coordinatorLayout), R.string.connect_fail, Snackbar.LENGTH_LONG).show();
}
}
catch (Exception e){
e.printStackTrace();
}
finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
@Override
protected void onPostExecute(JSONObject weather){
convertJSONtoArrayList(weather);
weatherArrayAdapter.updateData(weatherList);
weatherArrayAdapter.notifyDataSetChanged();
weatherListView.smoothScrollToPosition(0);
}
private void convertJSONtoArrayList(JSONObject forecast){
weatherList.clear();
try{
JSONArray list = forecast.getJSONArray("list");
for(int i = 0; i < list.length(); i++){
JSONObject day = list.getJSONObject(i);
JSONObject temperatures = day.getJSONObject("main");
JSONObject weather = day.getJSONArray("weather").getJSONObject(0);
Calendar hour = Calendar.getInstance();
hour.setTime(new SimpleDateFormat("yyyy-MM-dd' 'HH:mm:ss", Locale.US).parse(day.getString("dt_txt")));
weatherList.add(new Weather(
day.getLong("dt")*1000,
hour.getTimeInMillis(),
temperatures.getDouble("temp_min"),
temperatures.getDouble("temp_max"),
temperatures.getDouble("humidity"),
weather.getString("icon"),
weather.getString("description")));
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
}
这是我的WeatherArrayAdapter.java
class WeatherArrayAdapter extends ArrayAdapter<Weather> {
private static class ViewHolder{
ImageView conditionImageView;
TextView dayTextView;
TextView lowTextView;
TextView highTextView;
TextView humidityTextView;
TextView timeOfDayTextView;
TextView descriptionTextView;
}
//Create a map of used bitmaps to prevent re-downloading previously used bitmaps
private Map<String, Bitmap> bitmaps = new HashMap<>();
private List<Weather> weatherList;
WeatherArrayAdapter(Context context, List<Weather> forecast){
super(context, R.layout.item_list, forecast);
this.weatherList = forecast;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Log.e("ADAPTER", "getView()");
Weather day = weatherList.get(position);
ViewHolder viewHolder;
if(convertView == null){
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.list_item, parent, false);
viewHolder.conditionImageView = convertView.findViewById(R.id.conditionImageView);
viewHolder.dayTextView = convertView.findViewById(R.id.dayTextView);
viewHolder.highTextView = convertView.findViewById(R.id.highTextView);
viewHolder.lowTextView = convertView.findViewById(R.id.lowTextView);
viewHolder.humidityTextView = convertView.findViewById(R.id.humidityTextView);
viewHolder.timeOfDayTextView = convertView.findViewById(R.id.timeOfDayTextView);
viewHolder.descriptionTextView = convertView.findViewById(R.id.descriptionTextView);
}
else{
viewHolder = (ViewHolder) convertView.getTag();
}
if (bitmaps.containsKey(day.iconURL)) {
viewHolder.conditionImageView.setImageBitmap(bitmaps.get(day.iconURL));
} else {
new LoadImageTask(viewHolder.conditionImageView).execute(day.iconURL);
}
viewHolder.dayTextView.setText(day.dayOfWeek);
viewHolder.highTextView.setText(day.maxTemp);
viewHolder.lowTextView.setText(day.minTemp);
viewHolder.humidityTextView.setText(day.humidity);
viewHolder.timeOfDayTextView.setText(day.timeOfDay);
viewHolder.descriptionTextView.setText(day.description);
return convertView;
}
private class LoadImageTask extends AsyncTask<String, Void, Bitmap>{
ImageView imageView;
LoadImageTask(ImageView view){
this.imageView = view;
}
@Override
protected Bitmap doInBackground(String... strings) {
Bitmap bmp = null;
HttpURLConnection connection = null;
try{
URL url = new URL(strings[0]);
connection = (HttpURLConnection)url.openConnection();
try(InputStream inputStream = connection.getInputStream()){
bmp = BitmapFactory.decodeStream(inputStream);
bitmaps.put(strings[0], bmp);
}
catch (Exception e){
e.printStackTrace();
}
}
catch (Exception e){
e.printStackTrace();
}
finally {
if (connection != null) {
connection.disconnect();
}
}
return bmp;
}
@Override
protected void onPostExecute(Bitmap bitmap){
imageView.setImageBitmap(bitmap);
}
}
public void updateData(List<Weather> weatherList){
this.weatherList = weatherList;
}
}
Weather.java类
class Weather {
final String dayOfWeek, minTemp, maxTemp, humidity, iconURL, timeOfDay, description;
Weather(long timestamp, long timeOfDayMS, double minTemp, double maxTemp, double humidity, String iconName, String description){
NumberFormat numberFormat = NumberFormat.getNumberInstance();
numberFormat.setParseIntegerOnly(true);
this.dayOfWeek = convertTimestampToDay(timestamp);
this.timeOfDay = convertTimeOfDayToHM(timeOfDayMS);
this.minTemp = numberFormat.format(minTemp) + "\u00B0F";
this.maxTemp = numberFormat.format(maxTemp) + "\u00B0F";
this.humidity = numberFormat.format(humidity) + "%";
this.iconURL = "http://openweathermap.org/img/w/" + iconName + ".png";
this.description = description;
}
//Given a timestamp of milliseconds since epoch, we create a calendar and derive a day of the week name
private String convertTimestampToDay(long timestamp){
return new SimpleDateFormat("EEEE", Locale.US).format(getCalendar(timestamp).getTimeInMillis());
}
//Given a timestamp of milliseconds since epoch, we create a calendar and derive a time of day in hour:minute
private String convertTimeOfDayToHM(long timeOfDay){
return new SimpleDateFormat("h:mm a", Locale.US).format(getCalendar(timeOfDay).getTimeInMillis());
}
private Calendar getCalendar(long timestamp){
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timestamp);
calendar.setTimeZone(TimeZone.getTimeZone(Calendar.getInstance().getTimeZone().getDisplayName()));
return calendar;
}
}
最后我的list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/conditionImageView"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_weight="1"
android:contentDescription="@string/weather_image"
android:scaleType="fitCenter"
app:srcCompat="@mipmap/ic_launcher_round" />
<GridLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:columnCount="3"
android:rowCount="2"
android:useDefaultMargins="true"
android:visibility="visible">
<TextView
android:id="@+id/dayTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_columnWeight="1"
android:layout_row="0"
android:text="@string/day"
android:textAppearance="@android:style/TextAppearance.Material.Large" />
<TextView
android:id="@+id/lowTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_columnWeight="1"
android:layout_row="1"
android:text="@string/low" />
<TextView
android:id="@+id/highTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="2"
android:layout_columnWeight="1"
android:layout_row="1"
android:text="@string/high" />
<TextView
android:id="@+id/humidityTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="1"
android:layout_columnWeight="1"
android:layout_row="1"
android:text="@string/humidity" />
<TextView
android:id="@+id/timeOfDayTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="1"
android:layout_columnWeight="1"
android:layout_row="0"
android:text="@string/time" />
<TextView
android:id="@+id/descriptionTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="2"
android:layout_columnWeight="1"
android:layout_row="0"
android:text="@string/desc" />
</GridLayout>
</LinearLayout>
非常感谢任何帮助。
编辑我修复了超级构造函数,我从服务器获取数据 不幸的是,我的列表视图仍然是空白。 这是我从API获得的JSON的日志。
D/JSON: {"cod":"200","message":0.1604,"cnt":16,"list":[{"dt":1507280400,"main":{"temp":52,"temp_min":50.88,"temp_max":52,"pressure":1031.72,"sea_level":1039.36,"grnd_level":1031.72,"humidity":70,"temp_kf":0.62},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}],"clouds":{"all":0},"wind":{"speed":8.84,"deg":325.503},"sys":{"pod":"d"},"dt_txt":"2017-10-06 09:00:00"},{"dt":1507291200,"main":{"temp":56.17,"temp_min":55.34,"temp_max":56.17,"pressure":1032,"sea_level":1039.58,"grnd_level":1032,"humidity":65,"temp_kf":0.46},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}],"clouds":{"all":0},"wind":{"speed":8.95,"deg":326.001},"sys":{"pod":"d"},"dt_txt":"2017-10-06 12:00:00"},{"dt":1507302000,"main":{"temp":57.13,"temp_min":56.58,"temp_max":57.13,"pressure":1031.96,"sea_level":1039.61,"grnd_level":1031.96,"humidity":57,"temp_kf":0.31},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}],"clouds":{"all":0},"wind":{"speed":8.08,"deg":321.001},"sys":{"pod":"d"},"dt_txt":"2017-10-06 15:00:00"},{"dt":1507312800,"main":{"temp":51.49,"temp_min":51.22,"temp_max":51.49,"pressure":1031.85,"sea_level":1039.49,"grnd_level":1031.85,"humidity":63,"temp_kf":0.15},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04n"}],"clouds":{"all":64},"wind":{"speed":3.71,"deg":290.502},"sys":{"pod":"n"},"dt_txt":"2017-10-06 18:00:00"},{"dt":1507323600,"main":{"temp":46.91,"temp_min":46.91,"temp_max":46.91,"pressure":1031.69,"sea_level":1039.4,"grnd_level":1031.69,"humidity":81,"temp_kf":0},"weather":[{"id":801,"main":"Clouds","description":"few clouds","icon":"02n"}],"clouds":{"all":20},"wind":{"speed":4.85,"deg":223.502},"sys":{"pod":"n"},"dt_txt":"2017-10-06 21:00:00"},{"dt":1507334400,"main":{"temp":47.11,"temp_min":47.11,"temp_max":47.11,"pressure":1030.48,"sea_level":1038.22,"grnd_level":1030.48,"humidity":85,"temp_kf":0},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03n"}],"clouds":{"all":32},"wind":{"speed":7.74,"deg":249.001},"sys":{"pod":"n"},"dt_txt":"2017-10-07 00:00:00"},{"dt":1507345200,"main":{"temp":48.53,"temp_min":48.53,"temp_max":48.53,"pressure":1028.24,"sea_level":1035.82,"grnd_level":1028.24,"humidity":78,"temp_kf":0},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03n"}],"clouds":{"all":44},"wind":{"speed":9.42,"deg":237.503},"sys":{"pod":"n"},"dt_txt":"2017-10-07 03:00:00"},{"dt":1507356000,"main":{"temp":49.38,"temp_min":49.38,"temp_max":49.38,"pressure":1025.51,"sea_level":1033.19,"grnd_level":1025.51,"humidity":90,"temp_kf":0},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10n"}],"clouds":{"all":88},"wind":{"speed":13.04,"deg":237.506},"rain":{"3h":0.715},"sys":{"pod":"n"},"dt_txt":"2017-10-07 06:00:00"},{"dt":1507366800,"main":{"temp":55.61,"temp_min":55.61,"temp_max":55.61,"pressure":1023.56,"sea_level":1031.15,"grnd_level":1023.56,"humidity":89,"temp_kf":0},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"clouds":{"all":80},"wind":{"speed":14.45,"deg":250.003},"rain":{"3h":0.21},"sys":{"pod":"d"},"dt_txt":"2017-10-07 09:00:00"},{"dt":1507377600,"main":{"temp":61.41,"temp_min":61.41,"temp_max":61.41,"pressure":1021.72,"sea_level":1029.22,"grnd_level":1021.72,"humidity":78,"temp_kf":0},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"clouds":{"all":76},"wind":{"speed":14.79,"deg":265.003},"rain":{"3h":0.145},"sys":{"pod":"d"},"dt_txt":"2017-10-07 12:00:00"},{"dt":1507388400,"main":{"temp":62.38,"temp_min":62.38,"temp_max":62.38,"pressure":1020.3,"sea_level":1027.8,"grnd_level":1020.3,"humidity":69,"temp_kf":0},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"clouds":{"all":92},"wind":{"speed":13.76,"deg":280},"rain":{"3h":0.0049999999999999},"sys":{"pod":"d"},"dt_txt":"2017-10-07 15:00:00"},{"dt":1507399200,"main":{"temp":59.14,"temp_min":59.14,"temp_max":59.14,"pressure":1020.7,"sea_level":1028.21,"grnd_level":1020.7,"humidity":69,"temp_kf
答案 0 :(得分:0)
而不是仅仅添加notifyDataSetChanged()
将新arraylist
作为方法传递给weatherArrayAdapter
,然后调用notifyDataSetChanged()
。
在 weatherArrayAdapter类中创建一个类似这样的方法
public void updateData( List<Weather> weatherList ){
this.weatherList=weatherList;
}
在你的onPostEcecute中加上这个。
convertJSONtoArrayList(weather);
weatherArrayAdapter.updateData(weatherList);
weatherArrayAdapter.notifyDataSetChanged();
此外,您的预测列表不会在列表适配器代码中的任何位置使用。请检查一次;
修改强>:
您正在构造函数中将布局的id传递为-1
super(context, -1, forecast)
。相反,您需要传递您尝试膨胀的ID布局。