Пожалуйста, игнорируйте все ответы invalidate()
, invalidateViews()
, requestLayout()
, ... на этот вопрос.
Что нужно сделать (и, к счастью, также отмечено как правильный ответ), это для вызова notifyDataSetChanged()
на вашем адаптере .
Устранение неполадок
Если вызов notifyDataSetChanged()
не работает, все методы макета тоже не помогут. Поверьте мне, ListView
был должным образом обновлен. Если вы не можете найти разницу, вам нужно проверить, откуда поступают данные в вашем адаптере.
Если это просто коллекция, которую вы храните в памяти, проверьте, действительно ли вы удалили или добавили элемент (ы) в коллекцию перед вызовом notifyDataSetChanged()
.
Если вы работаете с базой данных или бэкэндом службы, вам придется вызвать метод, чтобы снова получить информацию (или манипулировать данными в памяти) перед вызовом notifyDataSetChanged()
.
Дело в том, что notifyDataSetChanged
работает, только если набор данных изменился. Так что это место, чтобы посмотреть, если вы не обнаружите, что изменения происходят через. Отладка при необходимости.
ArrayAdapter против BaseAdapter
Я обнаружил, что работа с адаптером, который позволяет вам управлять коллекцией, например, BaseAdapter, работает лучше. Некоторые адаптеры, такие как ArrayAdapter, уже управляют собственной коллекцией, что затрудняет доступ к соответствующей коллекции для обновлений. Это действительно просто ненужный дополнительный уровень сложности в большинстве случаев.
Пользовательский интерфейс
Это правда, что это должно вызываться из потока пользовательского интерфейса. В других ответах есть примеры того, как этого добиться. Однако это требуется, только если вы работаете с этой информацией вне потока пользовательского интерфейса. Это из службы или потока не пользовательского интерфейса. В простых случаях вы будете обновлять свои данные с помощью нажатия кнопки или другого действия / фрагмента. Так что все еще в потоке пользовательского интерфейса. Не нужно всегда вставлять этот runOnUiTrhead.
Быстрый пример проекта
Можно найти на https://github.com/hanscappelle/so-2250770.git. Просто клонируйте и откройте проект в Android Studio (gradle). Этот проект имеет здание MainAcitivity ListView
со всеми случайными данными. Этот список можно обновить с помощью меню действий.
Реализация адаптера, которую я создал для этого примера ModelObject, предоставляет сбор данных
public class MyListAdapter extends BaseAdapter {
/**
* this is our own collection of data, can be anything we
* want it to be as long as we get the abstract methods
* implemented using this data and work on this data
* (see getter) you should be fine
*/
private List<ModelObject> mData;
/**
* our ctor for this adapter, we'll accept all the things
* we need here
*
* @param mData
*/
public MyListAdapter(final Context context, final List<ModelObject> mData) {
this.mData = mData;
this.mContext = context;
}
public List<ModelObject> getData() {
return mData;
}
// implement all abstract methods here
}
Код от MainActivity
public class MainActivity extends Activity {
private MyListAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView list = (ListView) findViewById(R.id.list);
// create some dummy data here
List<ModelObject> objects = getRandomData();
// and put it into an adapter for the list
mAdapter = new MyListAdapter(this, objects);
list.setAdapter(mAdapter);
// mAdapter is available in the helper methods below and the
// data will be updated based on action menu interactions
// you could also keep the reference to the android ListView
// object instead and use the {@link ListView#getAdapter()}
// method instead. However you would have to cast that adapter
// to your own instance every time
}
/**
* helper to show what happens when all data is new
*/
private void reloadAllData(){
// get new modified random data
List<ModelObject> objects = getRandomData();
// update data in our adapter
mAdapter.getData().clear();
mAdapter.getData().addAll(objects);
// fire the event
mAdapter.notifyDataSetChanged();
}
/**
* helper to show how only changing properties of data
* elements also works
*/
private void scrambleChecked(){
Random random = new Random();
// update data in our adapter, iterate all objects and
// resetting the checked option
for( ModelObject mo : mAdapter.getData()) {
mo.setChecked(random.nextBoolean());
}
// fire the event
mAdapter.notifyDataSetChanged();
}
}
Дополнительная информация
Еще один приятный пост о силе listViews находится здесь: http://www.vogella.com/articles/AndroidListView/article.html