Android ListView не обновляется после notifyDataSetChanged

Мой код списка

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 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

     

Но это не обновляет ListView . Даже после перезапуска приложения обновленные элементы не отображаются. Мой ItemAdapter расширяет BaseAdapter

 public class ItemAdapter extends BaseAdapter{ private LayoutInflater inflater; private List items; private Context context; public ProjectListItemAdapter(Context context, List 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 в ItemFragment :

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

    то, что вы только что обновили перед вызовом notifyDataSetChanged() , не является private List items; полей private List items; адаптера private List items; но тождественно объявленное поле fragmentа. Адаптер по-прежнему сохраняет ссылку на список элементов, которые вы передали при создании адаптера (например, в файле onCreate). Самый короткий (в смысле количества изменений), но не элегантный способ заставить ваш код вести себя так, как вы ожидаете, просто заменить строку:

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

    с

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

    Более элегантное решение:

    1) удалить элементы private List items; из ItemFragment – нам нужно поддерживать ссылку на них только в адаптере

    2) изменить onCreate to:

     @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 items) { this.items = items; notifyDataSetChanged(); } 

    4) измените значение onResume на:

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

    Вы назначаете перезагруженные элементы глобальным переменным в onResume() , но это не отражается в classе ItemAdapter , потому что у него есть своя переменная экземпляра, называемая «items».

    Чтобы обновить ListView , добавьте параметр refresh () в class ItemAdapter который принимает данные списка, т.е. элементы

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

    update 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 

    Проблема в том, что вы никогда не рассказываете вашему адаптеру о списке новых элементов. Если вы не хотите передавать новый список вашему адаптеру (как вам кажется, нет), просто используйте items.addAll после вашего clear() . Это гарантирует, что вы измените тот же список, на который ссылается адаптер.

    Если адаптер уже установлен, установка его снова не обновит список. Вместо этого сначала проверьте, есть ли у listview адаптер, а затем вызывается соответствующий метод.

    Я думаю, что не очень хорошая идея создать новый экземпляр адаптера при настройке вида списка. Вместо этого создайте объект.

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

    Также вы можете попробовать запустить список обновлений в разделе «Интерфейс пользователя»:

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

    Если вы хотите обновить свой список, не имеет значения, хотите ли вы сделать это на onResume() , onCreate() или в какой-либо другой функции, первое, что вам нужно понять, это то, что вам не нужно будет создавать новый экземпляр адаптера, просто заново заполнить массивы вашими данными. Идея что-то похожее на это:

     private ArrayList 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() 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(); } 

    Поэтому в зависимости от этого ответа вы должны использовать тот же List в своем Fragment . В вашей первой инициализации адаптера вы заполняете свой список элементами и устанавливаете адаптер в свой список. После этого при каждом изменении ваших элементов вам нужно очистить значения из основных List items а затем снова заполнить их новыми элементами и вызвать notifySetDataChanged(); ,

    Вот как это работает:).

    Ответ от AlexGo сделал для меня трюк:

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

    Обновление списка работало для меня раньше, когда обновление было вызвано из события GUI, таким образом, в streamе пользовательского интерфейса.

    Однако, когда я обновляю список из другого события / streamа – то есть, вызов извне приложения, обновление не будет в streamе пользовательского интерфейса, и оно игнорирует вызов 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(); 

    Попробуйте это в onPause() classа Activity.

     adapter.setNotifyDataChanged() 

    должен сделать трюк.

    Попробуйте вот так:

     this.notifyDataSetChanged(); 

    вместо:

     adapter.notifyDataSetChanged(); 

    Вы должны notifyDataSetChanged() в ListView не для classа адаптера.

    Если ваш список содержится в самом адаптере, вызов функции, обновляющей список, также должен вызвать notifyDataSetChanged() .

    Запуск этой функции из streamа пользовательского интерфейса сделал для меня трюк:

    Функция refresh() внутри адаптера

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

    Затем, в свою очередь, запустите эту функцию из streamа пользовательского интерфейса

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

    Как отключить Безопасную загрузку, не входя в BIOS Setup?

    WPF привязка данных к интерфейсу, а не к фактическому объекту – возможность литья?

    Entity Framework. Есть ли способ автоматически загружать дочерние объекты без Include ()?

    Как предотвратить ifelse () от превращения объектов Date в числовые объекты

    Пустая страница, когда я использую FusionTablesLayer с Google Maps JavaScript API v3

    Почему Excel удаляет ведущие нули при отображении CSV-данных?

    Есть ли Java API для файлов mp4?

    Как элегантно игнорировать некоторые возвращаемые значения функции MATLAB?

    Файл Android APK: перезапустите старый файл APK в Google Play Store

    Переопределить вкладку как 4 пробела

    Лучшая структура веб-приложений для Java?

    java.net.SocketException: сброс соединения

    Почему zip-файл больше, чем исходный файл, особенно когда он является текстом?

    Функция не найдена в R doParallel ‘foreach’ – Ошибка в {: task 1 failed – “не удалось найти функцию” растровый “

    Остановить запланированный таймер при выключении tomcat

    Давайте будем гением компьютера.