2013-04-23 26 views
12

Mam bazę danych na serwerze iz Tabletu biorę pewne wartości z jednej tabeli w bazie danych. Wczytuję te informacje poprawnie do listy, ale chciałbym wiedzieć, dlaczego, gdy nastąpi zmiana, nic się nie dzieje, nawet jeśli używam notifyDataSetChanged();. Muszę powiedzieć, że do ładowania danych ładowania y używam AsyncTaskClass Tak więc, moim problemem jest to, że nie wiem, czy używać funkcji notifyDataSetChanged(); metoda poprawnie, ponieważ jeśli jest zmiana, chciałbym odświeżyć obraz. Oto część kodu klasy:Android: notifyDataSetChanged(); nie działa

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

     } 

    } 
} 
+0

żadnych awarii? nie chcesz, aby runOnUIThread po prostu ustawił adapter. Upewnij się, że candidatosList ma pewne wartości. – Triode

+0

Hi Triode, ładuję wszystkie wartości bazy danych na ekranie i działanie nie ulega awarii. Problem polega na tym, że nawet baza danych jest aktualizowana, interfejs użytkownika nie odświeża się z nowymi wartościami. – Katherine99

+0

@ Katherine99 jeśli moja odpowiedź rozwiązała problem ur, możesz zaznaczyć odpowiedź jako wybraną. :) –

Odpowiedz

68

Jednym z głównych powodów notifyDataSetChanged() nie będzie pracować dla Ciebie - jest

Twoja karta traci odniesienie do listy.

Po pierwszej inicjalizacji Adapter trwa odniesienie do arrayList i przekazuje ją swojej nadklasie. Ale jeśli ponownie zainicjujesz swój istniejący arrayList, utracisz referencję, a tym samym kanał komunikacji z Adapter.

Podczas tworzenia i dodawania nowej listy do Adapter. Zawsze należy przestrzegać następujących zasad:

  1. inicjalizację arrayList deklarując ją globalnie.
  2. Dodaj listę do adaptera bezpośrednio bez sprawdzania wartości pustych i pustych . Ustaw adapter bezpośrednio na liście (nie sprawdzaj żadnego warunku ). Adapter gwarantuje, że niezależnie od tego, gdzie dokonasz zmian w danych z arrayList zajmie się nim, ale nigdy nie straci referencji .
  3. Zawsze modyfikować dane w samej ArrayList (jeśli dane są całkowicie nowe niż można nazwać adapter.clear() i arrayList.clear() przed faktycznie dodawanie danych do listy), ale nie ustawia adapter tj Jeśli nowe dane jest zaludniony w arrayList niż tylko adapter.notifyDataSetChanged()

pozostać wiernym Dokumentacji.

+2

dziękuję bardzo, mój problem nie polegał na mocy adaptera. –

+1

Dziękuję bardzo, z twoim wyjaśnieniem zrozumiałem wiele rzeczy o adapterze, a widok listy znalazł rozwiązania dla wielu moich wątpliwości. –

+1

Dzięki za jasne wyjaśnienie. – huseyin

3

Adapter określający kompozycję układu! -> setListAdapter(): Zdefiniuj adapter dla ListView/GridView/Gallery ... , ale musisz określić dane!

Polecam, aby zainicjować "setListAdapter" w "onCreate" lub w konstruktorze. Po ustawieniu danych w adapterze (na przykład: adapter.setItem (yourData))

I TERAZ! Powinieneś zadzwonić do notifyDataSetChanged! Ponieważ zostały zmienione dane, ale widok nie jest odświeżenie i notifydatasetchanged() przeładować zawartość widoku (ListView/GridView/galeria ...)

Za dobrą praktykę i zrozumieć poprawnie polecam można użyć niestandardowego adaptera '' dzięki 'baseAdapter'

przeczytać i zrobić ten tutorial (i haver nauczyć się z tym): http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/

Przeczytaj dokumentację: http://developer.android.com/reference/android/widget/BaseAdapter.html

+0

Dzięki anthony, będę czytać te sieci, a ja dam ci znać o wynikach – Katherine99

4

Rzecz trzeba zmieniać się umieszczania

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

do onCreate(). i zwróć listę candidatosList z Asynctask. niż ustawić zegar do aktualizacji listy kandydatów.

+0

Niestety, kontynuuje bez odświeżania – Katherine99

+0

Sprawdź edytowane. – user1621629

+0

Witam, jeśli używam candidatosList.clear(); widok listy nie gromadzi żadnych danych podczas wykonywania działania – Katherine99

1

Jak Hissain describes above,

trzeba zachować odniesienie do listy

Oto jak mam go do pracy:

  1. Niech listę wysłanie do adaptera należy ustawić jako element instancji w działaniu

  2. w logice, która wykonuje zmianę danych, upewnij się, że aktualizuje tej samej liście instancji, że aktywność przekazywane do adaptera

  3. Potem dzwoni .notifyDataSetChanged(); pracował

Pamiętaj, że pozycja listView zaczyna się od 1, więc trzeba będzie zrobić (listViewPosition - 1) dla swojej java.util.List

3

To może być warta sprawdzenia, czy masz pusty nadpisanie dla registerDataSetObserver(). Android Studio dodał jeden dla mnie bez wykonywania połączenia do super. Dodanie go w sposób następujący wystarczyło, aby moje listView działa ponownie:

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

nie mam dużo reputacji do wypowiedzenia się na temat pana Hissain answer.It jest poprawna, ale chcę wspomnieć o jeszcze jednej rzeczy, że odniesienie do listy nie powinien się zmieniać. Jeśli zmienia się źródło danych, nie zmieniaj odniesienia do nowej listy. Działania należy wykonywać tylko na tym samym obiekcie listy. Aby to zrobić, wyczyść listę za pomocą polecenia clear(), a następnie dodaj dane do tej samej listy za pomocą metody add() lub metody addALL(), a następnie wywołaj metodę notifyDataSetChanged(). na przykład. Na pierwszej inicjalizacji listy

list = dataSource.getList(); 

następnie można dodać i usunąć zawartość z listy i nazywają notifyDataSetChanged() działa dobrze, ale jeśli w kodzie, próbuje się zmienić odwołanie do innego obiektu. Jak

list = dataSource.getList(); 

gdzie getlist() zwraca nową listę za każdym razem, stąd zmiany odniesienia do innej listy obiektu i wywołanie notifyDataSetChnaged nie ma wpływu na list.But jeśli getlist() zwraca samej liście obiektu, działa w porządku.

0

Funkcja aktualizacji powinna zostać wywołana z wątku interfejsu użytkownika. Moja odpowiedź jest rzeczywiście podobna do @ user1621629 na answer z tą różnicą, że używam rxJava, więc oto kod działa, że ​​rozwiąże ten problem dla mnie:

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

Tak ustawić wszystkie wykonanie w celu uzyskania danych na liście do wątku obliczeniowego, ale wyświetlając wynik w wątku interfejsu użytkownika.

Oto jak tworzę abonenta na to:

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(); 
     } 
    }); 
} 
...... 
Powiązane problemy