在 customAdapter.notifyDataSetChanged 之后 ListView 不更新

Posted

技术标签:

【中文标题】在 customAdapter.notifyDataSetChanged 之后 ListView 不更新【英文标题】:ListView does not update after customAdapter.notifyDataSetChanged 【发布时间】:2018-03-17 21:24:18 【问题描述】:

在我的程序中,我试图将天气状况列表更新为 ListView。我下载 JSON 并将其存储在 asyncTask 中,然后在 onPostExecute 和 notifyDataSetChanged 期间将数据解析到我的列表中。我在这里查看了几个相关的问题,但我不确定我错过了什么。这是我的 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_
android:layout_>

<ImageView
    android:id="@+id/conditionImageView"
    android:layout_
    android:layout_
    android:layout_weight="1"
    android:contentDescription="@string/weather_image"
    android:scaleType="fitCenter"
    app:srcCompat="@mipmap/ic_launcher_round" />

<GridLayout
    android:layout_
    android:layout_
    android:layout_weight="1"
    android:columnCount="3"
    android:rowCount="2"
    android:useDefaultMargins="true"
    android:visibility="visible">

    <TextView
        android:id="@+id/dayTextView"
        android:layout_
        android:layout_
        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_
        android:layout_
        android:layout_column="0"
        android:layout_columnWeight="1"
        android:layout_row="1"
        android:text="@string/low" />

    <TextView
        android:id="@+id/highTextView"
        android:layout_
        android:layout_
        android:layout_column="2"
        android:layout_columnWeight="1"
        android:layout_row="1"
        android:text="@string/high" />

    <TextView
        android:id="@+id/humidityTextView"
        android:layout_
        android:layout_
        android:layout_column="1"
        android:layout_columnWeight="1"
        android:layout_row="1"
        android:text="@string/humidity" />

    <TextView
        android:id="@+id/timeOfDayTextView"
        android:layout_
        android:layout_
        android:layout_column="1"
        android:layout_columnWeight="1"
        android:layout_row="0"
        android:text="@string/time" />

    <TextView
        android:id="@+id/descriptionTextView"
        android:layout_
        android:layout_
        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

【问题讨论】:

【参考方案1】:

不只是添加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 传递给您尝试膨胀的布局。

【讨论】:

我编辑了问题中的代码以反映这些更改,但我的 ListView 中仍然没有数据。 您没有在任何地方使用该列表......这就是它不显示数据的原因 代替这个 Weather day = getItem(position) 使用 Wea​​ther day = weatherList.get(position); 我改变了它,但它并没有解决问题。尝试在 WeatherArrayAdapter 的 getView 方法中记录任何内容都不会显示。这是正常现象还是问题的一部分? 您是否从服务器获取数据?使用日志检查..在此处发布日志

以上是关于在 customAdapter.notifyDataSetChanged 之后 ListView 不更新的主要内容,如果未能解决你的问题,请参考以下文章

秋的潇洒在啥?在啥在啥?

上传的数据在云端的怎么查看,保存在啥位置?

在 React 应用程序中在哪里转换数据 - 在 Express 中还是在前端使用 React?

存储在 plist 中的数据在模拟器中有效,但在设备中无效

如何在保存在 Mongoose (ExpressJS) 之前在模型中格式化数据

如何在保存在 Mongoose (ExpressJS) 之前在模型中格式化数据