Autore Topic: ArrayAdapter custom...mi stò impicciando il cervello...un chiarimento? Help me  (Letto 844 volte)

Offline AndreaNobili

  • Utente junior
  • **
  • Post: 75
  • Respect: 0
    • Mostra profilo
Ciao,
stò studiando sul libro di Massimo Carli.

Praticamente ho fatto un esempio in cui viene realizzato un ArrayAdapter customizzato che visualizza sullo schermo una lista di righe che al loro interno contengono 2 campi uno sotto l'altro: Firstname e SecondName (in pratica ogni riga contiene nome e cognome uno sotto l'altra)

Ho molti dubbi sul come l'Activity riesce a fare questa cosa però...

Ho un file main.xml per il layout molto semplice, semplicemente definisce una ListView che mostrerà le righe una sotto l'altra:

Codice: [Seleziona]
<?xml version="1.0" encoding="utf-8"?>

<!-- E' una particolare View che mostra oggetti in una lista scrollabile verticalmente. E' associata ad un ListAdapter  -->
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/arrayList"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
</ListView>

Poi lui definisce una riga personalizzata mediante il file custom_row.xml in cui in pratica definisce una tabella con 2 TableRow (una per il campo Firstname ed una per il campo Secondname):

Codice: [Seleziona]
<?xml version="1.0" encoding="utf-8"?>

<!-- Definisce la View associata a ciascuna riga della ListView (a ciascun elemento da visualizzare su una riga) -->
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/row_container"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="5px"
        android:background="@drawable/shape"
        android:shrinkColumns="0">
       
        <TableRow>
                <TextView
                        android:id="@+id/firstnameLabel"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/firstname_label"
                        android:textColor="@color/green">
                </TextView>
               
                <TextView
                        android:id="@+id/firstname"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_toRightOf="@+id/firstnameLabel"
                        android:layout_alignParentRight="true"
                        android:paddingLeft="10px"
                        android:text="default_value"
                        android:textColor="@color/blue">
                </TextView>
        </TableRow>
       
        <TableRow>
                <TextView
                        android:id="@+id/lastnameLabel"
                        android:layout_below="@+id/firstnameLabel"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/lastname_label"
                        android:textColor="@color/green">
                </TextView>
                <TextView
                        android:id="@+id/lastname"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_below="@+id/TextView01"
                        android:layout_toRightOf="@+id/firstnameLabel"
                        android:layout_alignParentRight="true"
                        android:paddingLeft="10px"
                        android:text="default_value"
                        android:textColor="@color/blue">
                </TextView>
        </TableRow>
</TableLayout>


Fin quì mi è tutto chiaro...ora però ho problemi a capire cosa faccia l'Activity...ho provato a commentarla e a leggere la documentaizione online ma alcune cose mi rimangono oscure:

Codice: [Seleziona]
package it.apogeo.android.cap05.customarrayadaptertest;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class CustomArrayAdapterTestActivity extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                // Impostiamo il Layout:
                setContentView(R.layout.main);
               
                // Otteniamo il riferimento alla ListView:
                ListView listView = (ListView) findViewById(R.id.arrayList);
               
                // Creiamo uno specifico ArrayAdapter ridefinendo il metodo getView tramite Override:
                ArrayAdapter<CustomItem> arrayAdapter = new ArrayAdapter<CustomItem>(this, R.layout.custom_row, R.id.firstnameLabel, createItems()) {
                       
                        /* Restituisce una View che mostra i dati nella posizione corrente dell'array:
                         * @param position è la posizione dell'elemento all'interno dell'insieme di dati dell'adapter che vogliamo visualizzare nella view
                         * @param convertView è la vecchia View da riusare (se possibile). Bisogna controllare che non sia null e che sia di un tipo appropriato. Se
                         *                   non è possibile convertire la View per mostrare i dati correttamente se ne può creare un'altra
                         * @param parent è la View padre a cui eventualmente questa View deve essere assegnata */
                        @Override
                        public View getView(int position, View convertView, ViewGroup parent){       
                                return getViewNoOptimized(position,convertView,parent);                                // La logica è implementata effettivamente dal metodo getViewNoOptimized
                        }

                        public View getViewNoOptimized(int position, View convertView, ViewGroup parent) {
                               
                                // Otteniamo l'elemento i-esimo (in posizione specificata da position):
                                CustomItem item = getItem(position);
                               
                                /* Ottengo il riferimento all'oggetto responsabile della trasformazione del documento XML del layout nella corrispondente struttura della
                                 * View descritta dalla classe LayoutInflater (è una classe usata per istanziare layout XML dentro il suo corrispettivo oggetto View) */
                                LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                               
                                /* Uso l'oggetto inflater appena creato per ottenere la View a partire dal documento XML che definisce una riga customizzata e ne metto il
                                 * riferimento dentro rowView: */
                                View rowView = inflater.inflate(R.layout.custom_row, null);
                               
                                // Otteniamo i campi informativi da riempire sull'oggetto rowView che rappresenta la riga corrente:
                                TextView firstnameView = (TextView)rowView.findViewById(R.id.firstname);                // Riferimento al campo firstname della riga corrente
                                TextView lastnameView = (TextView)rowView.findViewById(R.id.lastname);                        // Riferimento al campo lastname della riga corrente
                               
                                // Assegnamo i valori nella View presi dall'oggetto Item:
                                firstnameView.setText(item.firstname);
                                lastnameView.setText(item.lastname);
                                // Ritorniamo la View
                                return rowView;
                        }
                               
                       
                };
               
                // Lo impostiamo come adapter della listView:
                listView.setAdapter(arrayAdapter);
        }

        // Classe statica interna che rappresenta un generico oggetto da rappresentare che contiene solo i campi firstname e lastname:
        private static class CustomItem {
                public String firstname;
                public String lastname;
        }

        // Metodo di utilità che permette la creazione di un certo numero di istanze di test da visualizzare:
        private CustomItem[] createItems() {
               
                CustomItem[] items = new CustomItem[20];        // Creo un array di 20 oggetti di tipo CustomItem
               
                // Popolo l'array con valori del tipo: (Firstname_0 Lastname_0), (Firstname_1 Lastname_1), etc
                for (int i = 0; i < items.length; i++) {       
                        items[i] = new CustomItem();
                        items[i].firstname = "Firstname_" + i;
                        items[i].lastname = "Lastname_" + i;
                }
               
                return items;
        }
       
       
}       

Vediamo...vabbè per prima cosa come al solito setta il layout main.xml che contiene la ListView e subito dopo ne ottiene il riferimento mettendolo nella variabile listView (fin quì ok...)

Poi praticamente creo un nuovo ArrayAdapter (che come oggetti da visualizzare prende in considerazione il generic CustomItem che si è andato a definire tramite una classe statica interna e che rappresenta un generico item contenenti solo 2 campi: firstname e lastname).

Però praticamente credo che ora lui abbia l'esigenza di creare delle View particolari per ogni riga e perciò si ridefinisce il metodo getView che appunto gli dovrebbe restituire questa particolare View da visualizzare come riga della ListView (ho capito bene? è per questo che fà questa cosa?).

Creando lo specifico ArrayAdapter gli passa come parametri: this per il contesto, il riferimento al layout custom_row che rappresenta appunto lo schema della View da usare come riga, il riferimento alla TextView con id firstnameLabel nel file custom_row.xml (e quì non capisco perchè...a che gli serve? questo è il riferimento alla TextView che mostra solo l'intestazione e non il vero e proprio corpo informativo con i dati presi dall'array, perchè?) e poi createItems() che di fatto gli passa il riferimento ad un array di CustomItem popolato con 20 oggetti)

Ecco da quì inizio ad incasinarmi di brutto...

Per prima cosa si prende il riferimento all'oggetto corrente tramite il metodo getItem() (ma è un metodo definito dall'Adapter? è una cosa "automatica"? nel senso che è lui che di volta in volta tira fuori l'oggetto in posizione corrente senza che io me ne debba preoccupare?)

Poi crea un oggetto di tipo LayoutInflater che da quello che ho capito leggendo la documentazione online è una classe che mi serve per istanziare layout XML dentro una particolare View

In pratica che fà il seguente pezzo di codice?
Codice: [Seleziona]
/* Ottengo il riferimento all'oggetto responsabile della trasformazione del documento XML del layout nella corrispondente struttura della
                                 * View descritta dalla classe LayoutInflater (è una classe usata per istanziare layout XML dentro il suo corrispettivo oggetto View) */
                                LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                               
                                /* Uso l'oggetto inflater appena creato per ottenere la View a partire dal documento XML che definisce una riga customizzata e ne metto il
                                 * riferimento dentro rowView: */
                                View rowView = inflater.inflate(R.layout.custom_row, null);

Non sono riuscito a capire molto bene...ad occhio mi viene da pensare che prima crea questo oggetto inflate di tipo LayoutInflater e poi crea una generica View e tramite tale oggetto inflate gli "inietta" il layout definito nel file custom_row.xml

però boooo forse non ho capito una mazza...

Vabbè poi l'ultima parte dovrebbe essere semplice: ottengo i riferimenti ai 2 campi TextView nei quali voglio mettere i dati presi dall'Array e ci metto dentro tali dati ed alla fine ritorno la specifica Viw rowView...

mmm...se qualcuno riesce a colmare i miei dubbi gliene sarei molto grato

Grazie mille
Andrea





Offline Ricky`

  • Amministratore
  • Utente storico
  • *****
  • Post: 3489
  • Respect: +506
    • Github
    • Google+
    • rciovati
    • Mostra profilo
Re:ArrayAdapter custom...mi stò impicciando il cervello...un chiarimento? Help me
« Risposta #1 il: 03 Settembre 2011, 14:27:17 CEST »
0
Hai visto questo tutorial?

[medio] ListView con layout personalizzato tramite un custom ArrayAdapter - Android Developers Italia

Cmq la prossima volta dai dei titoli più significativi per favore.

Offline AndreaNobili

  • Utente junior
  • **
  • Post: 75
  • Respect: 0
    • Mostra profilo
Re:ArrayAdapter custom...mi stò impicciando il cervello...un chiarimento? Help me
« Risposta #2 il: 03 Settembre 2011, 15:48:24 CEST »
0
Hai visto questo tutorial?

[medio] ListView con layout personalizzato tramite un custom ArrayAdapter - Android Developers Italia

Cmq la prossima volta dai dei titoli più significativi per favore.

Ora gli darò un'occhiata (stavo studiando sul manuale di Carli ma aggiungere altre informazioni esterne può sempre far bene)

Scusa per il titolo poco significativo, cercherò di stare più attento...

Offline pivot

  • Nuovo arrivato
  • *
  • Post: 49
  • Respect: +1
    • Mostra profilo
  • Dispositivo Android:
    HTC Desire
  • Sistema operativo:
    Windows
Re:ArrayAdapter custom...mi stò impicciando il cervello...un chiarimento? Help me
« Risposta #3 il: 03 Settembre 2011, 22:32:47 CEST »
0
Il dubbio sul terzo parametro (firstnameLabel) è lecito, in effetti non serve a nulla per lo scopo dello specifico progetto.
Probabilmente fa così perché, per praticità, estende la classe ArrayAdapter per sfruttarne le funzionalità già implementate. A questo punto è costretto ad utilizzare uno dei costruttori di ArrayAdapter e la TextView è sempre obbligatoria. Tutto qui.

getItem(i) restituisce l'elemento nella posizione i-esima dell'array che contiene i tuoi dati. L'array lo passi all'ArrayAdapter nel costruttore quindi lui ti fa da wrapper per accedere all'elemento.

Per l'inflater, come dici tu prepara la view a partire dal layout come dichiarato nel xml relativo. E' la View della singola "riga" di ListView.

Chiaro ora?

Offline AndreaNobili

  • Utente junior
  • **
  • Post: 75
  • Respect: 0
    • Mostra profilo
Re:ArrayAdapter custom...mi stò impicciando il cervello...un chiarimento? Help me
« Risposta #4 il: 04 Settembre 2011, 11:18:36 CEST »
0
Il dubbio sul terzo parametro (firstnameLabel) è lecito, in effetti non serve a nulla per lo scopo dello specifico progetto.
Probabilmente fa così perché, per praticità, estende la classe ArrayAdapter per sfruttarne le funzionalità già implementate. A questo punto è costretto ad utilizzare uno dei costruttori di ArrayAdapter e la TextView è sempre obbligatoria. Tutto qui.

getItem(i) restituisce l'elemento nella posizione i-esima dell'array che contiene i tuoi dati. L'array lo passi all'ArrayAdapter nel costruttore quindi lui ti fa da wrapper per accedere all'elemento.

Per l'inflater, come dici tu prepara la view a partire dal layout come dichiarato nel xml relativo. E' la View della singola "riga" di ListView.

Chiaro ora?

Grazie,
ora mi è più chiaro...anche se però sono ancora un po' confuso del perchè a volte devo andarmi a definire un mio customer adapter...almeno per l'esempio fatto sul libro credo (e sottolineo credo...) che potrei fare la stessa identica cosa senza definirmi un mio adapter customizzato...

anche su questi 2 esempii quì di fatto implementano la stessa identica cosa (uno con un simpler adapter e l'altro con un customer adapter)
[medio] ListView con layout personalizzato tramite un custom ArrayAdapter - Android Developers Italia
[medio] ListView con layout personalizzato tramite un SimpleAdapter - Android Developers Italia

quindi mi sorge il dubbio...perchè mai dovrei realizzare un customer adapter quando la stessa cosa posso farla con un adapter già fornito nativamente da Android?

Forse i dubbi si chiariranno quando avrò veramente necessità di un mio customer adapter e dopo averci sbattuto la testa ne dovrò fare uno mio...booo

Per ora ho dato una studiata facendomi qualche esempio del libro ma poi sono passato direttamente all'uso degli adapter con gli spinner (molto facile) che di fatto è la cosa che mi serviva al momento nel mio progetto...te cosa mi consigli di fare? studiare meticolosamente l'argomento o continuare con quello che realmente mi serve e poi andarmi a studiare questi argomenti quando in futuro realmente mi servirano? (avendone comunque già visto un'infarinatura di base)

Tnx
Andrea

Offline Ricky`

  • Amministratore
  • Utente storico
  • *****
  • Post: 3489
  • Respect: +506
    • Github
    • Google+
    • rciovati
    • Mostra profilo
Re:ArrayAdapter custom...mi stò impicciando il cervello...un chiarimento? Help me
« Risposta #5 il: 04 Settembre 2011, 13:54:14 CEST »
0
quindi mi sorge il dubbio...perchè mai dovrei realizzare un customer adapter quando la stessa cosa posso farla con un adapter già fornito nativamente da Android?

Perchè a volte ti servono particolari funzionalità che puoi ottenere solo customizzando l'adapter :)

Offline AndreaNobili

  • Utente junior
  • **
  • Post: 75
  • Respect: 0
    • Mostra profilo
Re:ArrayAdapter custom...mi stò impicciando il cervello...un chiarimento? Help me
« Risposta #6 il: 04 Settembre 2011, 14:50:40 CEST »
0
Perchè a volte ti servono particolari funzionalità che puoi ottenere solo customizzando l'adapter :)

ehhh....potresti farmi un esempio? Perchè su quei 2 tutorial in fin dei conti realizza la stessa identica cosa una volta con un SimpleAdapter e l'altra volta con un adapter customizzato...quindi non capisco in quali casi potrebbe servirmi un adapter customizzato...

Offline pivot

  • Nuovo arrivato
  • *
  • Post: 49
  • Respect: +1
    • Mostra profilo
  • Dispositivo Android:
    HTC Desire
  • Sistema operativo:
    Windows
Re:ArrayAdapter custom...mi stò impicciando il cervello...un chiarimento? Help me
« Risposta #7 il: 04 Settembre 2011, 19:15:07 CEST »
0
Uno stesso problema può essere realizzato in infiniti modi. Quindi io posso scegliere di utilizzare un SimpleAdapter e tu estendere un ArrayAdapter.

L'esempio del libro aveva solo lo scopo di farti capire come derivare un adapter.
L'arrayAdapter è stato messo a disposizione dal framework android solo per gestire una singola stringa su un singolo textView. Nell'esempio avevi 2 stringhe e i rispettivi 2 textview, quindi o usavi un adapter personalizzato o utilizzavi il simplerAdapter. La soluzione migliore e quella che scegli tu caso per caso.