Android: notifyDataSetChanged (); не работает

У меня есть база данных на сервере, и из Tablet я беру некоторые значения из одной таблицы в базе данных. Я правильно загружаю эту информацию в список, но я хотел бы знать, почему, когда происходит изменение, ничего не происходит, даже если я использую notifyDataSetChanged(); , Я должен сказать, что для загрузки данных загрузки я использую AsyncTaskClass. Итак, моя проблема в том, что я не знаю, пользуетесь ли функцией notifyDataSetChanged (); Метод правильно, потому что если есть изменение, я хотел бы обновить изображение. Вот некоторая часть кода класса:

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.all_candidatos); candidatosList = new ArrayList<HashMap<String, String>>(); new CargarCandidatos().execute(); } // public void timer(){ // new CountDownTimer(tiempo, 100) { // // public void onTick(long millisUntilFinished) { // // } // // public void onFinish() { // // new CargarCandidatos().execute(); // // } // }.start();} /** * Background Async Task to Load all product by making HTTP Request * */ class CargarCandidatos extends AsyncTask<String, String, String> { /** * Before starting background thread Show Progress Dialog * */ @Override protected void onPreExecute() { super.onPreExecute(); pDialog = new ProgressDialog(Monitorizacion.this); pDialog.setMessage("Loading ..."); pDialog.setIndeterminate(false); pDialog.setCancelable(false); pDialog.show(); } /** * getting All products from url * */ protected String doInBackground(String... args) { List<NameValuePair> params = new ArrayList<NameValuePair>(); JSONObject json = jParser.makeHttpRequest(url_candidatos, "GET", params); Log.d("Candidatos: ", json.toString()); try { int success = json.getInt(TAG_SUCCESS); if (success == 1) { candidatos = json.getJSONArray(TAG_CANDIDATOS); for (int i = 0; i < candidatos.length(); i++) { JSONObject c = candidatos.getJSONObject(i); // Storing each json item in variable String nserie = c.getString(TAG_NSERIE); String dni = c.getString(TAG_DNI); String nombre = c.getString(TAG_NOMBRE); String test = c.getString(TAG_TEST); String pregunta = c.getString(TAG_PREGUNTA); String bateria = c.getString(TAG_BATERIA); // creating new HashMap HashMap<String, String> map = new HashMap<String, String>(); // adding each child node to HashMap key => value map.put(TAG_NSERIE, nserie); map.put(TAG_DNI, dni); map.put(TAG_NOMBRE, nombre); map.put(TAG_TEST, test); map.put(TAG_PREGUNTA, pregunta); map.put(TAG_BATERIA, bateria); // adding HashList to ArrayList candidatosList.add(map); } } } catch (JSONException e) { e.printStackTrace(); } return null; } /** * After completing background task Dismiss the progress dialog * **/ protected void onPostExecute(String file_url) { pDialog.dismiss(); runOnUiThread(new Runnable() { public void run() { /** * Updating parsed JSON data into ListView * */ adapter = new SimpleAdapter( Monitorizacion.this, candidatosList, R.layout.list_item, new String[] { TAG_NSERIE, TAG_DNI, TAG_NOMBRE, TAG_TEST, TAG_PREGUNTA, TAG_BATERIA}, new int[] { R.id.id, R.id.dni, R.id.nombre, R.id.test, R.id.pregunta, R.id.bateria}); setListAdapter(adapter); adapter.notifyDataSetChanged(); // timer(); } }); } } } 

Одна из основных причин notifyDataSetChanged() не будет работать для вас – есть,

Ваш адаптер теряет ссылку на ваш список .

Когда вы сначала инициализируете Adapter он получает ссылку на свой arrayList и передает его своему суперклассу. Но если вы arrayList инициализируете свой существующий arrayList он arrayList ссылку и, следовательно, канал связи с Adapter .

При создании и добавлении нового списка в Adapter . Всегда следуйте этим рекомендациям:

  1. Инициализируйте arrayList , объявив его глобально.
  2. Добавьте список в адаптер напрямую, не проверяя нулевые и пустые значения. Установите адаптер в список напрямую (не проверяйте какое-либо условие). Адаптер гарантирует, что везде, где вы вносите изменения в данные arrayList он позаботится об этом, но никогда не потеряет ссылку.
  3. Всегда изменяйте данные в самом массиве (если ваши данные совершенно новы, чем вы можете вызвать adapter.clear() и arrayList.clear() прежде чем добавлять данные в список), но не устанавливайте адаптер, т. arrayList.clear() Если новые данные arrayList в список arrayList не только adapter.notifyDataSetChanged()

Оставайтесь верными Документации.

Вещь, которую вам нужно изменить,

 runOnUiThread(new Runnable() { public void run() { /** * Updating parsed JSON data into ListView * */ adapter = new SimpleAdapter( Monitorizacion.this, candidatosList, R.layout.list_item, new String[] { TAG_NSERIE, TAG_DNI, TAG_NOMBRE, TAG_TEST, TAG_PREGUNTA, TAG_BATERIA}, new int[] { R.id.id, R.id.dni, R.id.nombre, R.id.test, R.id.pregunta, R.id.bateria}); setListAdapter(adapter); adapter.notifyDataSetChanged(); // timer(); } }); 

В OnCreate (). И верните список candidatosList из Asynctask. Чем установить таймер для обновления списка candidatosList.

Адаптер определяет компоновку макета! -> setListAdapter (): определить адаптер для ListView / GridView / Gallery … но вам нужно указать данные!

Я рекомендую вам инициализировать 'setListAdapter' в 'onCreate' или в конструкторе. После установки данных в адаптер (пример: adapter.setItem (yourData))

И сейчас ! Вы должны позвонить notifyDataSetChanged! Поскольку вы изменили данные, но представление не обновляется и notifydatasetchanged () перезагружает содержимое представления (ListView / GridView / Gallery …)

Для хорошей практики и понимания правильно я рекомендую вам использовать «пользовательский адаптер», используя « baseAdapter »,

Прочтите и сделайте этот учебник (я бы с этим учился): http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/

Прочтите документацию: http://developer.android.com/reference/android/widget/BaseAdapter.html

Возможно, стоит проверить, есть ли у вас пустое переопределение для registerDataSetObserver() . Android Studio добавила один для меня, не выполняя вызов super. Дополнить его следующим образом было достаточно, чтобы снова запустить мой ListView:

 @Override public void registerDataSetObserver(DataSetObserver observer) { super.registerDataSetObserver(observer); } 

Как описывает Хисейн выше ,

Вам необходимо сохранить ссылку на список

Вот как я получил его на работу:

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

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

  3. Затем вызывается .notifyDataSetChanged (); работал

Помните, что позиция listView начинается с 1, поэтому вам нужно будет сделать (listViewPosition-1) для вашего java.util.List

У меня не так много репутации, чтобы прокомментировать ответ г-на Хисейна. Это правильно, но я хочу упомянуть еще одну вещь, которая не должна изменяться ссылкой на список. Если базовый источник данных изменяется, не изменяйте ссылку на новый список. Действия должны выполняться только в том же объекте списка. Чтобы сделать то же самое, очистите список, используя clear (), а затем добавьте данные в тот же список, используя add () или addALL (), а затем вызовите notifyDataSetChanged (). например. При первой инициализации списка

 list = dataSource.getList(); 

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

 list = dataSource.getList(); 

Где getList () каждый раз возвращает новый список, поэтому ссылка на какой-либо другой объект списка и вызов notifyDataSetChnaged не влияет на список. Но если getList () возвращает один и тот же объект списка, он отлично работает.

Функция обновления должна вызываться из потока пользовательского интерфейса. Мой ответ на самом деле похож на ответ @ user1621629 с той разницей, что я использую rxJava, так что вот рабочий код, который решает эту проблему для меня:

 this.subscriber = myAdapter.getSubscriber(); // keep for unsubscribe in destroy dataSource.subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()).subscribe(this.subscriber); 

Поэтому я устанавливаю все выполнение, чтобы получить данные для списка в поток вычислений, но показывая результат в потоке пользовательского интерфейса.

Вот как я создаю подписчика для этого:

 public class MyListAdapter extends RecyclerView.Adapter<LocationListAdapter.ViewHolder> { private List<ListItem> mDataset = new ArrayList<>(); public Subscriber<ListItem[]> getSubscriber() { return Subscribers.create(new Action1<ListItem[]>() { @Override public void call(ListItem[] listItems) { mDataset.clear(); mDataset.addAll(Arrays.asList(listItems)); notifyDataSetChanged(); } }); } ......