Autore Topic: ListView che cambia?  (Letto 1114 volte)

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
ListView che cambia?
« il: 25 Marzo 2011, 00:19:26 CET »
0
Ho realizzato una lista con un'immagine a sinistra e del testo a destra utilizzando una ListView ed 1 ArrayAdapter, quando clicco un elemento della lista compare l'immagine a sinistra del nome però accade una cosa strana, se effettuo lo scroll le immagini appaiono e scompaiono a loro piacimento senza nessuna logica apparente, sarà lo scroll che resetta qualcosa, vi è mai accaduta sta cosa?

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:ListView che cambia?
« Risposta #1 il: 25 Marzo 2011, 09:52:53 CET »
0
Dipende tantissimo da come hai implementato il metodo getView dell'adapter della lista.

Android utilizza un motore molto particolare per la visualizzazione delle liste in modo efficiente tentando di riusare al massimo oggetti già allocati. Se non hai scritto per bene quella parte di codice, potresti vedere "cose strane" nella lista.

L'esempio su come si scrivono in modo esatto le liste lo trovi qui: List14.java | Android Developers

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re:ListView che cambia?
« Risposta #2 il: 25 Marzo 2011, 10:04:28 CET »
0
mmm diciamo che il codice è identico al mio ho usato anche l'holder solo che non ho queste 2 linee di codice :

// Cache the LayoutInflate to avoid asking for a new one each time.           
mInflater = LayoutInflater.from(context);

private static final String[] DATA = Cheeses.sCheeseStrings;

in effetti lui si tiene in Cache il Layout potrebbe essere quello perchè se nello scroll a me lo ridisegna in questo modo dovrebbe tenerlo in memoria....ora provo!

la secondo linea private static final String[] DATA = Cheeses.sCheeseStrings; non sò proprio a che serve..+ un array ma che è Cheeses.sCheeseStrings; ??

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:ListView che cambia?
« Risposta #3 il: 25 Marzo 2011, 10:07:41 CET »
0
Se tu il LayoutInflater lo prendi dentro il controllo convertView==null allora poco importa (io preferisco questa versione, ma sono punti di vista e sopratutto di ottimizzazione diversa).

I dati sono invece strani. Tu dove li prendi? Tecnicamente dovresti averli nel costruttore dell'adapter (o come variabile membro della ListActivity).

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re:ListView che cambia?
« Risposta #4 il: 25 Marzo 2011, 10:18:53 CET »
0
Io l'inflate lo faccio nella convertView==null ed i dati li carico nell'adapter all'interno dell'onCreate specificando il layout, l'id della textview ed ovviamente l'array eppure quando scrollo la lista sembra impazzire.....

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:ListView che cambia?
« Risposta #5 il: 25 Marzo 2011, 10:23:41 CET »
0
Io l'inflate lo faccio nella convertView==null ed i dati li carico nell'adapter all'interno dell'onCreate specificando il layout, l'id della textview ed ovviamente l'array eppure quando scrollo la lista sembra impazzire.....

E' arrivato il momento di postare il tuo codice.

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re:ListView che cambia?
« Risposta #6 il: 25 Marzo 2011, 10:40:09 CET »
0
Ekkilo

OnCreate
Codice (Java): [Seleziona]
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.list_audio, file_array);
ListView list = (ListView)findViewById(R.id.list_audio);
list.setAdapter(adapter);

GetView
Codice (Java): [Seleziona]
@Override
public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if(convertView==null){
                LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(context, null);
                holder.cek = (ImageView)convertView.findViewById(R.id.cek_img);
                holder.testo_audio = (TextView)convertView.findViewById(R.id.text_audio);
                convertView.setTag(holder);
        }else{
                holder = (ViewHolder)convertView.getTag();
        }
        if(v==position) holder.cek.setImageResource(R.id.yes_cek);
        else holder.cek.setImageResource(R.id.no_cek);
        holder.testo_audio.setText(R.id.nome_file);
        return convertView;
}

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:ListView che cambia?
« Risposta #7 il: 25 Marzo 2011, 12:07:34 CET »
0
In quel codice manca qualche cosa... tipo tutto il resto!

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re:ListView che cambia?
« Risposta #8 il: 25 Marzo 2011, 12:50:01 CET »
0
Emmmm cioè ???

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:ListView che cambia?
« Risposta #9 il: 25 Marzo 2011, 14:05:07 CET »
0
Cioè che hai postato solo una parte del codice, non tutto il codice.

Sfortunatamente ho la sfera di cristallo in riparazione e quindi mi viene difficile capire cosa rappresentano le variabili v, context (che nel tuo caso particolare... non rappresenta il contesto!!!  :-o )!

Attendo il codice o la riparazione della sfera? :p

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re: ListView che cambia?
« Risposta #10 il: 25 Marzo 2011, 14:22:22 CET »
0
Scusami in effetti il context era sbagliato è this :-) il parametro v non è altro che la posizione della view cliccata (in pratica gli dico che se la losizione della view cliccata è uguale a position allora deve visualizzare l'immagine del cekbox cekkato altrimenti l'altra). Spero di.essermi.spiegato altrimenti appena rientro ti posto il codice

Sent from my GT-I9000 using Tapatalk

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re: ListView che cambia?
« Risposta #11 il: 25 Marzo 2011, 14:53:49 CET »
+1
Scusami in effetti il context era sbagliato è this :-) il parametro v non è altro che la posizione della view cliccata (in pratica gli dico che se la losizione della view cliccata è uguale a position allora deve visualizzare l'immagine del cekbox cekkato altrimenti l'altra). Spero di.essermi.spiegato altrimenti appena rientro ti posto il codice

Sent from my GT-I9000 using Tapatalk

Allora non ci siamo! ;)

Tralasciando il fatto che contex non è nemmeno this, io parlo della riga dell'inflater, non puoi gestire le azioni in questo modo: non puoi essere sicuro (anzi, normalmente non avviene proprio) che quando clicchi su un oggetto della lista venga chiamato nuovamente il metodo getView, fatta eccezione che tu non l'abbia gestito da qualche altra parte del codice che non hai postato (ovvero chiamare il notify dell'adapter al momento del click).

Ma in ogni caso le viste non hanno uno stato e non mantengono uno stato! Tu metti in cache (usando l'holder) la struttura fisica di una View (ovvero le varie view che la compongono) ma non il contenuto della view stessa! L'holder ti permette di usare locazioni di memoria dove sono già state create le View evitando operazioni lentissime come l'inflater o il findViewById.

L'holder NON fa altro: tutti i dati sono sotto il tuo controllo.

Facciamo un esempio pratico: hai una lista con 100 View, ma sul dispositivo ne vedi 10 alla volta. Ogni View ha al suo interno 3 TextView.
L'ottimizzazione del metodo holder consiste nel fare soltanto circa 10 inflater e 10*(N componenti che compongono la View) findViewById.
In questo caso quindi abbiamo 10 inflater + 10*3 = 40 operazioni di recupero di XML ed new vari.
Senza l'holder avresti avuto 100 inflater + 100*3 = 400 operazioni... bel il 1000% in più!!!

Compreso questo bisogna però capire cosa cambia usando l'holder.
Stiamo visualizzando la nostra lista con 10 elementi.
Per questi primi 10 elementi verrà chiamato il metodo getView con contentView uguale a null (è la prima volta visualizziamo la lista).
Supponiamo che il primo elemento contenga nelle 3 TextView li stringhe "Visita il mio Blog", "www.MarcoDuff.com", "si, è pubblicità occulta".

Scrolliamo in basso la lista per visualizzare l'11mo elemento e... MAGIA: viene chiamato nuovamente il metodo getView ma questa volta contentView non è null!!!
In particolare, android dice questo: "visto che scrollando verso il basso non puoi più vedere il primo elemento della lista, io te lo ripasso al volo adesso, cosi che ti faccio evitare di fare nuovamente l'inflater ed il findViewById e mi togli un sacco di fatica a me ed al GarbageCollection!". Furbo android no?

Off-Topic:
Noto che la mia spiegazione sta diventando demenziale... sarà la fame?

Supponiamo che tu abbia un codice del tipo: if(position==11) allora aggiorna solo la TextView3 con "è il sito Blog più bello del mondo!" tu ti ritroverai le tre TextView impostate in questo modo:
"Visita il mio Blog", "www.MarcoDuff.com", "è il sito Blog più bello del mondo!"

Tu hai aggiornato solo la terza TextView... le prime due sono rimaste esattamente uguali a prima (ovvero uguali a quelle passate da android per riutilizzare le risorse).

Andando al tuo problema.
Da quanto si capisce, al click di un oggetto della lista tu imposti v = alla posizione appena cliccata. Quello che accadrà nel codice è che probabilmente scrollando sempre la lista verrà visualizzata solo e sempre 1 item selezionato, visto che quando scompare un elemento dalla lista e successivamente riappare viene disegnato nuovamente tramite il getView e viene prese in considerazione solo l'ultimo valore della v memorizzato, non tutti.

Soluzione: devi implementare una lista di v dentro il tuo adapter uguale al numero di elementi e cambiare i valori nella lista, in modo da averli tutti!

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re:ListView che cambia?
« Risposta #12 il: 25 Marzo 2011, 23:20:02 CET »
0
Premettendo che ci ho messo 3 ore a capire quello che avevi scritto :D il metodo getView viene richiamato perchè sull'onClickItem richiamo il metodo listupdate nel cui interno vi è un adapter.notifyDataChanged quindi il metodo getView viene richiamato ad ogni click, cambia qualcosa ? :)

Comunque ammazza che bella spiegazione bravo Marco ! ;)

PS: In effetti nell'inflate non va il this ma R.layout.row_audio purtroppo ero in ufficio stamattina e non avevndo il codice sottomano l'ho scritto io senza i suggerimenti di eclipse :-)

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:ListView che cambia?
« Risposta #13 il: 28 Marzo 2011, 21:08:11 CEST »
0
Premettendo che ci ho messo 3 ore a capire quello che avevi scritto :D il metodo getView viene richiamato perchè sull'onClickItem richiamo il metodo listupdate nel cui interno vi è un adapter.notifyDataChanged quindi il metodo getView viene richiamato ad ogni click, cambia qualcosa ? :)

No, non cambia nulla... anzi, che probabilmente l'unica "v" valida è solo l'ultima, tutte le altre view della lista tornano allo stato iniziale ad ogni click.