notifyListSetChanged后,Android ListView不刷新

我的ListFragment代码

public class ItemFragment extends ListFragment { private DatabaseHandler dbHelper; private static final String TITLE = "Items"; private static final String LOG_TAG = "debugger"; private ItemAdapter adapter; private List<Item> items; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.item_fragment_list, container, false); return view; } @Override public void onCreate(Bundle savedInstanceState) { super.setHasOptionsMenu(true); super.onCreate(savedInstanceState); getActivity().setTitle(TITLE); dbHelper = new DatabaseHandler(getActivity()); items = dbHelper.getItems(); adapter = new ItemAdapter(getActivity().getApplicationContext(), items); this.setListAdapter(adapter); } @Override public void onResume() { super.onResume(); items.clear(); items = dbHelper.getItems(); //reload the items from database adapter.notifyDataSetChanged(); } @Override public void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); if(dbHelper != null) { //item is edited Item item = (Item) this.getListAdapter().getItem(position); Intent intent = new Intent(getActivity(), AddItemActivity.class); intent.putExtra(IntentConstants.ITEM, item); startActivity(intent); } } } 

我的ListView

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> 

但是这不刷新ListView 。 即使在重新启动应用程序后,更新的项目也不会显示。 我的ItemAdapter扩展了BaseAdapter

 public class ItemAdapter extends BaseAdapter{ private LayoutInflater inflater; private List<Item> items; private Context context; public ProjectListItemAdapter(Context context, List<Item> items) { super(); inflater = LayoutInflater.from(context); this.context = context; this.items = items; } @Override public int getCount() { return items.size(); } @Override public Object getItem(int position) { return items.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ItemViewHolder holder = null; if(convertView == null) { holder = new ItemViewHolder(); convertView = inflater.inflate(R.layout.list_item, parent,false); holder.itemName = (TextView) convertView.findViewById(R.id.topText); holder.itemLocation = (TextView) convertView.findViewById(R.id.bottomText); convertView.setTag(holder); } else { holder = (ItemViewHolder) convertView.getTag(); } holder.itemName.setText("Name: " + items.get(position).getName()); holder.itemLocation.setText("Location: " + items.get(position).getLocation()); if(position % 2 == 0) { convertView.setBackgroundColor(context.getResources().getColor(R.color.evenRowColor)); } else { convertView.setBackgroundColor(context.getResources().getColor(R.color.oddRowColor)); } return convertView; } private static class ItemViewHolder { TextView itemName; TextView itemLocation; } } 

有人可以帮忙吗?

看看ItemFragment中的onResume方法:

 @Override public void onResume() { super.onResume(); items.clear(); items = dbHelper.getItems(); // reload the items from database adapter.notifyDataSetChanged(); } 

在调用notifyDataSetChanged()之前,您刚才更新的内容不是适配器的字段private List<Item> items; 而是片段的相同声明的字段。 适配器仍然存储对创build适配器时传递的项目列表的引用(例如,在片段的onCreate中)。 最短的(根据变化的数量),但不是优雅的方式来使你的代码像你期望的那样行事,只不过是取代这一行:

  items = dbHelper.getItems(); // reload the items from database 

  items.addAll(dbHelper.getItems()); // reload the items from database 

更优雅的解决scheme:

1)删除项目private List<Item> items;ItemFragment – 我们只需要在适配器中引用它们

2)更改为创build:

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); super.setHasOptionsMenu(true); getActivity().setTitle(TITLE); dbHelper = new DatabaseHandler(getActivity()); adapter = new ItemAdapter(getActivity(), dbHelper.getItems()); setListAdapter(adapter); } 

3)在ItemAdapter中添加方法:

 public void swapItems(List<Item> items) { this.items = items; notifyDataSetChanged(); } 

4)改变你的onResume为:

 @Override public void onResume() { super.onResume(); adapter.swapItems(dbHelper.getItems()); } 

您正在将重新加载的项目分配给onResume()全局variables项目,但这不会反映在ItemAdapter类中,因为它具有自己的实例variables(称为“项目”)。

为了刷新ListView ,在ItemAdapter类中添加一个refresh(),它接受列表数据,即项目

 class ItemAdapter { ..... public void refresh(List<Item> items) { this.items = items; notifyDataSetChanged(); } } 

用下面的代码更新onResume()

 @Override public void onResume() { super.onResume(); items.clear(); items = dbHelper.getItems(); //reload the items from database **adapter.refresh(items);** } 

在onResume()改变这一行

 items = dbHelper.getItems(); //reload the items from database 

 items.addAll(dbHelper.getItems()); //reload the items from database 

问题是,你永远不会告诉你的适配器关于新的项目列表。 如果你不想传递一个新的列表到你的适配器(因为它看起来你没有),那么只需在你的clear()之后使用items.addAll 。 这将确保您正在修改适配器所引用的列表。

如果适配器已经设置,再次设置不会刷新列表视图。 首先检查一下listview是否有一个适配器,然后调用适当的方法。

我认为在设置列表视图时创build适配器的新实例并不是一个好主意。 相反,创build一个对象。

 BuildingAdapter adapter = new BuildingAdapter(context); if(getListView().getAdapter() == null){ //Adapter not set yet. setListAdapter(adapter); } else{ //Already has an adapter adapter.notifyDataSetChanged(); } 

你也可以尝试在UI线程上运行刷新列表:

 activity.runOnUiThread(new Runnable() { public void run() { //do your modifications here // for example adapter.add(new Object()); adapter.notifyDataSetChanged() } }); 

如果你想更新你的listview并不重要,如果你想在onResume()onCreate()或其他函数上做到这一点,首先你必须意识到的是,你不需要创build一个新的实例的适配器,只需再次使用您的数据填充数组。 这个想法是类似于这样的:

 private ArrayList<String> titles; private MyListAdapter adapter; private ListView myListView; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); myListView = (ListView) findViewById(R.id.my_list); titles = new ArrayList<String>() for(int i =0; i<20;i++){ titles.add("Title "+i); } adapter = new MyListAdapter(this, titles); myListView.setAdapter(adapter); } @Override public void onResume(){ super.onResume(); // first clear the items and populate the new items titles.clear(); for(int i =0; i<20;i++){ titles.add("New Title "+i); } adapter.notifySetDataChanged(); } 

所以根据这个答案,你应该在你的Fragment使用相同的List<Item> 。 在你的第一个适配器初始化中,你用列表填充你的列表,并将适配器设置为你的列表视图。 之后,在你的项目的每一个变化,你必须清除主要List<Item> items的值,并再次填充您的新项目,并调用notifySetDataChanged();

这是如何工作的:)。

AlexGo的回答对我来说是个窍门:

 getActivity().runOnUiThread(new Runnable() { @Override public void run() { messages.add(m); adapter.notifyDataSetChanged(); getListView().setSelection(messages.size()-1); } }); 

当更新被GUI事件触发之前,列表更新为我工作,因此在UI线程中。

但是,当我从另一个事件/线程更新列表 – 即从应用程序外的调用,更新将不会在UI线程中,它忽略了对getListView的调用。 像上面那样用runOnUiThread调用更新对我来说是个诀窍。 谢谢!!

尝试这个

 @Override public void onResume() { super.onResume(); items.clear(); items = dbHelper.getItems(); //reload the items from database adapter = new ItemAdapter(getActivity(), items);//reload the items from database adapter.notifyDataSetChanged(); } 
 adpter.notifyDataSetInvalidated(); 

在Activity类的onPause()方法中试试这个。

 adapter.setNotifyDataChanged() 

应该做的伎俩。

尝试像这样:

 this.notifyDataSetChanged(); 

代替:

 adapter.notifyDataSetChanged(); 

你必须通知notifyDataSetChanged()ListView而不是适配器类。

如果您的列表包含在适配器本身中,则调用更新列表的函数也应该调用notifyDataSetChanged()

从UI线程运行这个函数为我做了窍门:

适配器内的refresh()函数

 public void refresh(){ //manipulate list notifyDataSetChanged(); } 

然后依次从UI线程运行此function

 getActivity().runOnUiThread(new Runnable() { @Override public void run() { adapter.refresh() } });