2013-04-23 19 views
12

Ho un database in un server e da un tablet prendo alcuni valori da una tabella nel database. Carico queste informazioni correttamente in una lista ma vorrei sapere perché quando c'è un cambiamento, non succede nulla anche se io uso notifyDataSetChanged();. Devo dire che per caricare i dati di caricamento si usa AsyncTaskClass Quindi, il mio problema è che non so se usare notifyDataSetChanged(); metodo corretto, perché se c'è una modifica mi piacerebbe aggiornare l'immagine. Ecco una parte del codice della classe:Android: notifyDataSetChanged(); non funziona

@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

alcun crash? non vuoi che runOnUIThread semplicemente imposta l'adattatore. Assicurati che candidatosList stia avendo alcuni valori. – Triode

+0

Ciao Triode, carico tutti i valori del database sullo schermo e l'attività non si blocca. il problema è che anche il database viene aggiornato, l'interfaccia utente non si aggiorna con i nuovi valori. – Katherine99

+0

@ Katherine99 se la mia risposta è stata risolta, puoi contrassegnare la risposta come selezionata. :) –

risposta

68

Uno dei motivi principali notifyDataSetChanged() non funziona per voi - è,

L'adattatore perde riferimento alla tua lista.

Quando si inizializza per la prima volta il Adapter prende un riferimento del proprio arrayList e lo passa alla sua superclasse. Ma se reinizializzi il tuo esistente arrayList, perde il riferimento e, quindi, il canale di comunicazione con Adapter.

Quando si crea e si aggiunge un nuovo elenco allo Adapter. Seguire sempre queste linee guida:

  1. Inizializzare il arrayList dichiarandolo globalmente.
  2. Aggiungere l'elenco direttamente all'adattatore senza controllo per valori nulli e vuoti . Impostare direttamente la scheda sulla lista (non verificare le condizioni di ). L'adattatore ti garantisce che, ovunque vengano apportate modifiche ai dati dello arrayList, si prenderà cura di esso, ma non si perderà mai il riferimento .
  3. modificare sempre i dati nella arrayList stesso (se i dati sono completamente nuovo di quanto è possibile chiamare adapter.clear() e arrayList.clear() prima in realtà l'aggiunta di dati alla lista), ma non impostare l'adattatore cioè se i nuovi dati è popolata nel arrayList non solo adapter.notifyDataSetChanged()

rimanere fedele alla Documentazione.

+2

grazie mille, il mio problema non era avere fiducia nella potenza dell'adattatore. –

+1

Grazie mille, con la tua spiegazione ho capito molte cose sulla scheda e la visualizzazione elenco ha trovato anche soluzioni per molti dei miei dubbi. –

+1

Grazie per questa chiara spiegazione. – huseyin

3

Un adattatore definisce il comportement del layout! -> setListAdapter(): definisce l'adattatore per ListView/GridView/Gallery ... ma è necessario specificare i dati!

Si consiglia di inizializzare 'setListAdapter' in 'onCreate' o nel costruttore. Dopo aver impostato i dati nell'adattatore (esempio: adapter.setItem (yourData))

E ORA! Dovresti chiamare notifyDataSetChanged! Perché si sono cambiati i dati, ma la vista non è rinfrescare e notifydatasetchanged() ricaricare il contenuto della vista (ListView/GridView/Galleria ...)

Per una buona pratica e capire correttamente raccomando a di utilizzare un 'adattatore personalizzato' utilizzando 'baseAdapter'

Leggere e fare questo tutorial (I haver imparare con questo): http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/

Leggere la documentazione: http://developer.android.com/reference/android/widget/BaseAdapter.html

+0

Grazie anthony, leggerò quelle web e ti farò sapere i risultati – Katherine99

4

La cosa è necessario modificare è mettere il

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

nella OnCreate(). e restituire la lista candidatosList da Asynctask. di impostare il timer per l'aggiornamento dell'elenco elenchi candidati.

+0

Scusa, continua senza rinfrescare – Katherine99

+0

Si prega di controllare il Modificato. – user1621629

+0

Ciao se uso candidatosList.clear(); la vista elenco non contiene dati quando eseguo l'attività – Katherine99

1

Come Hissain describes above,

è necessario mantenere un riferimento alla lista

Ecco come ho ottenuto di lavorare:

  1. Facciamo la lista essere inviato all'adattatore essere impostato come membro di istanza nell'attività

  2. Nella logica che esegue una modifica dei dati, assicurarsi che aggiorna la stessa istanza lista che l'attività passò all'adattatore

  3. quindi chiamando .notifyDataSetChanged(); lavorato

Ricordate quella posizione listView comincia a 1, in modo da avere a che fare (listViewPosition - 1) per il vostro java.util.List

3

potrebbe essere la pena di verificare se si dispone di un override vuoto per registerDataSetObserver(). Android Studio ne ha aggiunto uno per me senza implementare la chiamata a super. L'aggiunta nel modo seguente è stato sufficiente per ottenere il mio listView lavorare di nuovo:

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

Non ho molto reputazione di commentare il signor Hissain answer.It è corretto, ma io voglio parlare di una cosa che il riferimento alla lista non dovrebbe cambiare Se l'origine dati sottostante sta cambiando, non modificare il riferimento alla nuova lista. Le azioni devono essere eseguite solo sullo stesso oggetto elenco. Per fare lo stesso, cancellare l'elenco usando clear() e quindi aggiungere i dati allo stesso elenco usando add() o addALL() e quindi chiamare notifyDataSetChanged(). per esempio. Sulla prima inizializzazione della lista

list = dataSource.getList(); 

allora si può aggiungere e rimuovere il contenuto dalla lista e chiamare notifyDataSetChanged() funziona bene, ma se nel codice, si cerca di modificare il riferimento per l'altro oggetto. Come

list = dataSource.getList(); 

dove getList() restituisce il nuovo elenco ogni volta, quindi le modifiche riferimento a qualche altro oggetto lista e chiamando notifyDataSetChnaged non ha impatto sul list.But se getList() restituisce lo stesso oggetto lista, funziona bene.

0

La funzione di aggiornamento deve essere richiamata dal thread dell'interfaccia utente. La mia risposta è in realtà simile a @ user1621629 di answer con quella differenza che sto usando rxJava, quindi ecco il codice di lavoro che a risolvere questo problema per me:

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

Così ho impostato tutta l'esecuzione al fine di ottenere i dati per la lista al thread di calcolo, ma mostrando il risultato nel thread dell'interfaccia utente.

Ecco come ho creato per questo abbonato:

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