Как обновить список просмотров Android?

Как обновить Android ListView после добавления / удаления динамических данных?

Вызовите notifyDataSetChanged() в свой объект Adapter после изменения данных в этом адаптере.

Некоторые дополнительные особенности того, как / когда вызывать notifyDataSetChanged() можно просмотреть в этом видео ввода-вывода Google .

Также вы можете использовать это:

 myListView.invalidateViews(); 

наслаждаться!

Пожалуйста, проигнорируйте все invalidate() , invalidateViews() , requestLayout() , … ответы на этот вопрос.

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

Исправление проблем

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

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

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

Дело в том, что notifyDataSetChanged работает только в том случае, если dataset изменился. Таким образом, это место для поиска, если вы не найдете изменений. При необходимости отлаживайте.

ArrayAdapter vs BaseAdapter

Я нашел, что работает с адаптером, который позволяет вам управлять коллекцией, например, BaseAdapter работает лучше. Некоторые адаптеры, такие как ArrayAdapter, уже управляют своей собственной коллекцией, что затрудняет доступ к соответствующей коллекции для обновлений. В большинстве случаев это просто лишний лишний уровень сложности.

Пользовательский интерфейс

Это правда, что это нужно вызывать из streamа пользовательского интерфейса. В других ответах есть примеры того, как добиться этого. Однако это требуется только в том случае, если вы работаете над этой информацией из-за пределов пользовательского интерфейса. Это из службы или неинтерфейса. В простых случаях вы будете обновлять свои данные с помощью нажатия кнопки или другого действия / fragmentа. Так что все еще в streamе пользовательского интерфейса. Не нужно всегда вызывать этот 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 mData; /** * our ctor for this adapter, we'll accept all the things * we need here * * @param mData */ public MyListAdapter(final Context context, final List mData) { this.mData = mData; this.mContext = context; } public List 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 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 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

Вызовы выполняются всякий раз, когда вы хотите:

 runOnUiThread(run); 

OnCreate() , вы устанавливаете свой runnable thread:

 run = new Runnable() { public void run() { //reload content arraylist.clear(); arraylist.addAll(db.readAll()); adapter.notifyDataSetChanged(); listview.invalidateViews(); listview.refreshDrawableState(); } }; 

У меня возникли проблемы с динамическим обновлением моего списка.

Вызовите notifyDataSetChanged () в своем адаптере.

Некоторые дополнительные особенности того, как / когда вызывать notifyDataSetChanged (), можно просмотреть в этом видео ввода-вывода Google.

notifyDataSetChanged () не работает должным образом в моем случае [я вызвал notifyDataSetChanged из другого classа]. Как раз в том случае, когда я редактировал ListView в текущей Activity (Thread). Это видео благодаря Кристоферу дало окончательный намек.

В моем втором classе я использовал

 Runnable run = new Runnable(){ public void run(){ contactsActivity.update(); } }; contactsActivity.runOnUiThread(run); 

для доступа к обновлению () из моей активности. Это обновление включает

 myAdapter.notifyDataSetChanged(); 

чтобы Адаптер обновил представление. Насколько я могу судить, работал отлично.

Если вы используете SimpleCursorAdapter, попробуйте вызвать requery () в объекте Cursor.

если вы еще не удовлетворены ListView Refreshment, вы можете посмотреть этот fragment, это для загрузки спискаView из базы данных. Фактически, вам нужно просто перезагрузить ListView после выполнения любой операции CRUD. Это не лучший способ кода, но он обновит ListView по вашему желанию.

Это работает для меня …. если вы найдете лучшее решение, пожалуйста, поделитесь …

 .......
 ......
 делайте свои операции с CRUD.
 ......
 .....
 DBAdapter.open ();
 DBAdapter.insert_into_SingleList ();
 // Принесите этот DB_results и добавьте его в список как его содержимое ....
                                             ls2.setAdapter (новый ArrayAdapter (DynTABSample.this,
     android.R.layout.simple_list_item_1, DBAdapter.DB_ListView));
                                             DBAdapter.close ();

Решения, предлагаемые людьми в этом сообщении, работают или не зависят в основном от версии вашего устройства Android. Например, чтобы использовать метод AddAll, вы должны поместить android: minSdkVersion = “10” в ваше устройство Android.

Чтобы решить эти вопросы для всех устройств, я создал свой собственный метод в своем адаптере, и использование внутри метода add и remove наследует от ArrayAdapter, что без проблем обновляет ваши данные.

Мой код: используя собственный class данных RaceResult, вы используете свою собственную модель данных.

ResultGpRowAdapter.java

 public class ResultGpRowAdapter extends ArrayAdapter { Context context; int resource; List data=null; public ResultGpRowAdapter(Context context, int resource, List objects) { super(context, resource, objects); this.context = context; this.resource = resource; this.data = objects; } @Override public View getView(int position, View convertView, ViewGroup parent) { ........ } //my own method to populate data public void myAddAll(List items) { for (RaceResult item:items){ super.add(item); } } 

ResultsGp.java

 public class ResultsGp extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { ........... ........... ListView list = (ListView)findViewById(R.id.resultsGpList); ResultGpRowAdapter adapter = new ResultGpRowAdapter(this, R.layout.activity_result_gp_row, new ArrayList()); //Empty data list.setAdapter(adapter); .... .... .... //LOAD a ArrayList with data ArrayList data = new ArrayList(); data.add(new RaceResult(....)); data.add(new RaceResult(....)); ....... adapter.myAddAll(data); //Your list will be udpdated!!! 

Если вы хотите сохранить свою позицию прокрутки во время обновления, и вы можете сделать это:

 if (mEventListView.getAdapter() == null) { EventLogAdapter eventLogAdapter = new EventLogAdapter(mContext, events); mEventListView.setAdapter(eventLogAdapter); } else { ((EventLogAdapter)mEventListView.getAdapter()).refill(events); } public void refill(List events) { mEvents.clear(); mEvents.addAll(events); notifyDataSetChanged(); } 

Подробную информацию см. В списке Android ListView: поддерживайте свою позицию прокрутки при обновлении .

Просто используйте myArrayList.remove(position); внутри слушателя:

  myListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, android.view.View view, int position, long id) { myArrayList.remove(position); myArrayAdapter.notifyDataSetChanged(); } }); 

Вам нужно использовать один объект этого списка, в котором данные, которые вы накачиваете в ListView . Если ссылка – это изменение, то notifyDataSetChanged() не работает. При удалении элементов из представления списка также удаляйте их из списка, который вы используете, является ли это ArrayList <> или что-то еще, а затем notifyDataSetChanged() на объекте вашего адаптера class.

Итак, посмотрим, как я это сделал в своем адаптере, см. Ниже

 public class CountryCodeListAdapter extends BaseAdapter implements OnItemClickListener{ private Context context; private ArrayList dObj; private ViewHolder holder; private Typeface itemFont; private int selectedPosition=-1; private ArrayList completeList; public CountryCodeListAdapter(Context context, ArrayList dObj) { this.context = context; this.dObj=dObj; completeList=new ArrayList(); completeList.addAll(dObj); itemFont=Typeface.createFromAsset(context.getAssets(), "CaviarDreams.ttf"); } @Override public int getCount() { return dObj.size(); } @Override public Object getItem(int position) { return dObj.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View view, ViewGroup parent) { if(view==null){ holder = new ViewHolder(); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.states_inflator_layout, null); holder.textView = ((TextView)view.findViewById(R.id.stateNameInflator)); holder.checkImg=(ImageView)view.findViewById(R.id.checkBoxState); view.setTag(holder); }else{ holder = (ViewHolder) view.getTag(); } holder.textView.setText(dObj.get(position).getCountryName()); holder.textView.setTypeface(itemFont); if(position==selectedPosition) { holder.checkImg.setImageResource(R.drawable.check); } else { holder.checkImg.setImageResource(R.drawable.uncheck); } return view; } private class ViewHolder{ private TextView textView; private ImageView checkImg; } public void getFilter(String name) { dObj.clear(); if(!name.equals("")){ for (CountryDataObject item : completeList) { if(item.getCountryName().toLowerCase().startsWith(name.toLowerCase(),0)){ dObj.add(item); } } } else { dObj.addAll(completeList); } selectedPosition=-1; notifyDataSetChanged(); notifyDataSetInvalidated(); } @Override public void onItemClick(AdapterView parent, View view, int position, long id) { Registration reg=(Registration)context; selectedPosition=position; reg.setSelectedCountryCode("+"+dObj.get(position).getCountryCode()); notifyDataSetChanged(); } } 

После удаления данных из представления списка вам необходимо вызвать refreshDrawableState() . Вот пример:

 final DatabaseHelper db = new DatabaseHelper (ActivityName.this); db.open(); db.deleteContact(arg3); mListView.refreshDrawableState(); db.close(); 

и метод deleteContact в classе DatabaseHelper будет несколько похож

 public boolean deleteContact(long rowId) { return db.delete(TABLE_NAME, BaseColumns._ID + "=" + rowId, null) > 0; } 

Мне не удалось получить notifyDataSetChanged (), чтобы работать над обновлением моего SimpleAdapter, поэтому вместо этого я попытался сначала удалить все представления, которые были прикреплены к родительскому макету с помощью removeAllViews (), а затем добавить ListView, и это сработало, что позволило мне обновить UI:

 LinearLayout results = (LinearLayout)findViewById(R.id.results); ListView lv = new ListView(this); ArrayList> list = new ArrayList>(); SimpleAdapter adapter = new SimpleAdapter( this, list, R.layout.directory_row, new String[] { "name", "dept" }, new int[] { R.id.name, R.id.dept } ); for (...) { HashMap map = new HashMap(); map.put("name", name); map.put("dept", dept); list.add(map); } lv.setAdapter(adapter); results.removeAllViews(); results.addView(lv); 

Для меня после изменения информации в базе данных sql ничто не могло обновить представление списка (чтобы быть конкретным расширяемым представлением списка), поэтому, если notifyDataSetChanged () не помогает, вы можете сначала очистить свой список и добавить его снова после этого вызова notifyDataSetChanged (). Например

 private List> arrayList; List array1= getArrayList(...); List array2= getArrayList(...); arrayList.clear(); arrayList.add(array1); arrayList.add(array2); notifyDataSetChanged(); 

Надеюсь, это имеет смысл для вас.

при использовании SimpleCursorAdapter можно вызвать changeCursor (newCursor) на адаптере.

Я был тем же самым, когда во fragmentе я хотел заполнить ListView (в одном TextView) с MAC-адресом устройств BLE, отсканированных в течение некоторого времени.

Я сделал это:

 public class Fragment01 extends android.support.v4.app.Fragment implements ... { private ListView listView; private ArrayAdapter arrayAdapter_string; ... @Override public void onActivityCreated(Bundle savedInstanceState) { ... this.listView= (ListView) super.getActivity().findViewById(R.id.fragment01_listView); ... this.arrayAdapter_string= new ArrayAdapter(super.getActivity(), R.layout.dispositivo_ble_item, R.id.fragment01_item_textView_titulo); this.listView.setAdapter(this.arrayAdapter_string); } @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { ... super.getActivity().runOnUiThread(new RefreshListView(device)); } private class RefreshListView implements Runnable { private BluetoothDevice bluetoothDevice; public RefreshListView(BluetoothDevice bluetoothDevice) { this.bluetoothDevice= bluetoothDevice; } @Override public void run() { Fragment01.this.arrayAdapter_string.add(new String(bluetoothDevice.toString())); Fragment01.this.arrayAdapter_string.notifyDataSetChanged(); } } 

Затем ListView начал динамически заполнять MAC-адрес найденных устройств.

Я думаю, это зависит от того, что вы подразумеваете под обновлением. Вы имеете в виду, что дисплей графического интерфейса должен быть обновлен или вы имеете в виду, что дочерние представления должны быть обновлены, чтобы вы могли программно вызвать getChildAt (int) и получить представление, соответствующее тому, что находится в адаптере.

Если вы хотите обновить графический интерфейс GUI, тогда вызовите notifyDataSetChanged () на адаптере. GUI будет обновлен при следующем перерисовании.

Если вы хотите, чтобы иметь возможность вызвать getChildAt (int) и получить представление, которое отражает то, что есть в адаптере, а затем вызвать layoutChildren (). Это приведет к восстановлению дочернего представления из данных адаптера.

У меня был ArrayList, который я хотел отобразить в списке. ArrayList содержит элементы из mysql. Я переопределил метод Refresh, и в этом методе я использовал tablelayout.removeAllViews (); а затем повторил процесс получения данных из базы данных. Но перед этим обязательно очистите ArrayList или любую структуру данных, иначе новые данные будут добавлены к старой.

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

 @Override public void onDestroy() { if (MainActivity.isInFront == true) { if (MainActivity.adapter != null) { MainActivity.adapter.notifyDataSetChanged(); } MainActivity.listView.setAdapter(MainActivity.adapter); } } 

Если вы идете по линиям проводников Android, и вы используете ContentProviders для получения данных из Database и вы показываете их в ListView с помощью CursorLoader и CursorAdapters , то все изменения в связанных данных будут автоматически отображаться в ListView.

getContext().getContentResolver().notifyChange(uri, null); на курсор в ContentProvider будет достаточно, чтобы отразить изменения. Нет необходимости в дополнительной работе.

Но когда вы не используете их все, вам нужно сообщить адаптеру, когда dataset меняется. Также вам нужно повторно заполнить / перезагрузить свой dataset (например, список), а затем вам необходимо вызвать notifyDataSetChanged() на адаптере.

notifyDataSetChanged() работает, если изменений в datset нет. Вот комментарий выше метода в docs-

 /** * Notifies the attached observers that the underlying data has been changed * and any View reflecting the data set should refresh itself. */ 

Я смог получить notifyDataSetChanged только, получив новые данные адаптера, затем сбросив адаптер для представления списка, а затем сделав вызов так:

  expandableAdapter = baseFragmentParent.setupEXLVAdapter(); baseFragmentParent.setAdapter(expandableAdapter); expandableAdapter.notifyDataSetChanged(); 

по другому варианту – метод onWindowFocusChanged , но уверен, что он чувствителен и нуждается в некотором дополнительном кодировании для кого-то

  override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) // some controls needed programList = usersDBHelper.readProgram(model.title!!) notesAdapter = DailyAdapter(this, programList) notesAdapter.notifyDataSetChanged() listview_act_daily.adapter = notesAdapter } 

Подумайте, что вы передали список своему адаптеру.
Использование:

list.getAdapter().notifyDataSetChanged()

для обновления вашего списка.

Проще всего просто создать новый Adaper и отказаться от старого:

 myListView.setAdapter(new MyListAdapter(...)); 
  • Android ListView с кнопкой удаления
  • Включение общего JavaScript в WebViewClient
  • Проблема с быстрым прокруткой с помощью ListAdapter и SectionIndexer
  • Android ListView setSelection (), похоже, не работает
  • ASP.NET MVC - просмотр с несколькими моделями
  • Android Alternate row Colors в ListView
  • Показывать пустое представление, когда ListView пуст
  • BaseAdapter заставляет ListView выходить из строя при прокрутке
  • Как реализовать держатель вида?
  • listView динамический элемент добавления
  • Listview itemclick не работает
  • Давайте будем гением компьютера.