2011-12-16 15 views
15

Ho una vista LinearLayout che contiene già diversi elementi. Voglio aggiungere molte più viste ad esso, a livello di programmazione. E poiché questo è all'interno di un ScrollView, tutto verrà fatto scorrere.Qual è il modo più rapido per aggiungere più viste a un LinearLayout?

Quindi quello che faccio è passare attraverso la mia lista e aggiungere nuove istanze della mia visualizzazione personalizzata ad esso. Quella vista personalizzata gonfia un layout XML e aggiunge alcuni metodi.

Questo approccio funziona bene. Il problema è che è super lento, anche senza alcun codice pazzo ... una lista con 10 elementi richiede circa 500ms per istanziare. Dal punto di vista dell'esperienza utente, è difficile da digerire.

La mia domanda è, è questo l'approccio corretto/migliore? Android sembra impiegare molto tempo a gonfiare il layout, anche se "R.layout.my_list_item" è semplicissimo. Mi chiedo se c'è un modo forse per riutilizzare i layout "gonfiati" per ulteriori visualizzazioni, un po 'come mettere in cache l'analisi più complessa?

Ho provato a farlo con uno ListView (e adattatore e un wrapper) e sembra essere molto più veloce. Il problema è che non posso usare un semplice ListView; il mio layout è più complesso di un semplice elenco (lo stesso LinearLayout contiene icone personalizzate aggiuntive e ha un altro genitore con un numero ancora maggiore di visualizzazioni prima che venga spostato dallo ScrollView).

Ma esiste un modo per utilizzare un adattatore per LinearLayout? Sarebbe più veloce di provare ad aggiungere le visualizzazioni da solo?

Qualsiasi aiuto è apprezzato. Mi piacerebbe farlo più velocemente.

Il codice segue.

attività principale:

// The LinearLayout that will contain everything 
lineList = (LinearLayout) findViewById(R.id.lineList); 

// Add a lot of items for testing 
for (int i = 0; i < 10; i++) { 
    addListItem("Item number " + i); 
} 

protected void addListItem(String __title) { 
    MyListItem li; 
    li = new MyListItem(this); 
    li.setTitle(__title); 
    lineList.addView(li);  
} 

MyListItem:

public class MyListItem extends RelativeLayout { 

    protected TextView textTitle; 

    public MyListItem(Context __context) { 
     super(__context); 
     init(); 
    } 

    public MyListItem(Context __context, AttributeSet __attrs) { 
     super(__context, __attrs); 
     init(); 
    } 

    public MyListItem(Context __context, AttributeSet __attrs, int __attrsdefStyle) { 
     super(__context, __attrs, __attrsdefStyle); 
     init(); 
    } 

    protected void init() { 
     // Inflate the XML layout 
     LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     inflater.inflate(R.layout.my_list_item, this); 

     // Create references 
     textTitle = (TextView)findViewById(R.id.textTitle); 
    } 

    public void setTitle(String __text) { 
     textTitle.setText(__text); 
    } 
} 

Quello che sto cercando di realizzare è questo. Considerare questo layout:

Basic layout

Questo layout è un (scatola esterna) FrameLayout contenente (in grigio), un (rettangolo interno, sulla parte superiore) ImageViewTextView e un LinearLayout (rettangolo interno, sul fondo). Questo rettangolo LinearLayout è quello che sto popolando in modo dinamico con alcuni elementi.

Dopo Io popolo, voglio il risultato finale di essere presente (in cui ogni nuovo rettangolo è un nuovo MyListItem esempio):

Populated layout

Cioè, tutto è scorrevole (l'immagine di sfondo, per esempio, è allineato in alto). Il LinearLayout non è scorrevole da solo (tutto il resto segue), quindi perché un ListView, da quello che so, non funzionerebbe molto bene nel mio caso.

+1

Quanti elementi hai in quell'attività e hai qualche classe personalizzata che eredita elementi dell'interfaccia utente? –

+0

Le visualizzazioni delle liste sono così veloci perché riciclano i layout degli articoli. Gonfiano il numero di layout degli elementi richiesti per riempire lo schermo. Quando scorri verso il basso, una vista in alto viene nascosta e una in basso viene mostrata. La listview prende il vecchio, invisibile dall'alto e lo mette con i nuovi dati in basso. Evita l'inflazione costosa. Complessivamente: questo qui sembra * molto * inefficiente, sono abbastanza sicuro di ciò che si possa fare con un listview. Se mostri ciò che hai provato e pubblichi uno schizzo del tuo layout, possiamo aiutarti a capirlo. –

+0

Paul: non molti elementi. Forse 4 o 5. Sì, alcuni di loro sono classi personalizzate che ereditano dal framework di base. alextsc: grazie per la spiegazione. Ho aggiunto un diagramma che spiega meglio la mia situazione, quindi è chiaro se e come potrei usare un ListView invece (o meno). – zeh

risposta

7

3 opzioni:

  1. sostituire tutto con un controllo ListView, con le altre icone genitore e personalizzato come una vista intestazione per il ListView. ListView è più veloce, perché crea solo Views in base alle esigenze.

  2. creare Programatically il contenuto di my_list_item invece di gonfiare, potrebbe essere più veloce

  3. L'utilizzo di ViewStubs può consentire di caricare viste on-demand.

  4. Forse non sta caricando le viste ma i dati? in tal caso, preparare i dati in un thread in background.

+0

Grazie per questa risposta diretta e pratica. Aggiungerei "creare le viste su un thread separato" all'elenco (come suggerito dall'utente1031312 in un commento sotto). A parte questo, penso che riassumi bene le possibili soluzioni. – zeh

1

Basta usare un ListView!

È il più semplice da configurare e da mantenere. Si definisce un layout XML per la riga elenco e un layout XML per la vista che contiene l'intero elenco. ListAdapter fa il resto per te.

Basta creare un:

List<HashMap<String, String>> services = new ArrayList<HashMap<String, String>>(); 

... e scorrere i dati per aggiungere le voci che ti piace mappa. Quindi imposta questa mappa sul tuo ListAdapter. Se 10 articoli o 100 elementi, ListAdapter creerà un elenco con tanti elementi.

Esempio:

public void updateProductList(String searchTerm) { 
     createOrOpenDB(this); 
     Cursor cursor = (searchTerm!=null)? dbAdapter.fetchWhere(TBL_NAME, KEY_NAME+" LIKE '%"+searchTerm+"%'") 
       : dbAdapter.fetchAll(TBL_NAME); 
     int rows = cursor.getCount(); 
     if (rows<=0) return; 
     services.clear(); //clear current list 
     for (int i=0; i<rows; i++) { 
      HashMap<String, String> map = new HashMap<String, String>(); 
      cursor.moveToPosition(i); 
      map.put(KEY_NAME, "" + cursor.getString(cursor.getColumnIndex(KEY_NAME))); 
      map.put(KEY_DESC, "" + cursor.getString(cursor.getColumnIndex(KEY_DESC))); 
      map.put(KEY_COST, "" + cursor.getDouble(cursor.getColumnIndex(KEY_COST))); 
      services.add(map); 
     } 
     cursor.close(); 
     closeDB(); 

     ListAdapter adapter = new SimpleAdapter(this, services, R.layout.products_view_row, 
       new String[] {KEY_NAME, KEY_DESC, KEY_COST}, 
       new int[] {R.id.listViewText1, R.id.listViewText2, R.id.listViewText3}); 
     setListAdapter(adapter); 
    } 
+0

Grazie. Ho creato un 'ListView' con un adattatore adeguato in altre parti della stessa applicazione, tuttavia, il problema non è con l'implementazione di un' ListView'. Il motivo per cui non sto usando un ListView qui è perché non sembra realizzare ciò di cui ho bisogno (scorrendo altri elementi non di elenco, non di intestazione in parallelo). Mi piacerebbe essere smentito, ma la risposta è più complessa di "usa solo una listview". – zeh

+0

Ohh capisco. Allora quello che vuoi è questo: http://stackoverflow.com/questions/3192595/android-listview-that-does-not-scroll (vedi risposta accettata) accoppiato con un ScrollView per incapsulare l'intero layout. – Ozzy

+0

Err, come ho detto sul post originale, questo è esattamente quello che sto facendo, ma sto avendo un problema con le prestazioni (l'aggiunta manuale di elementi a LinearLayout è lenta). – zeh

2

A ListView è la strada da percorrere.

Si dice che il layout sia troppo complesso. Ma è del tutto normale per gonfiare un layout complesso da bambino. Per esempio un layout che ha il testo e poi un'icona:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" > 
    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" /> 
    <ImageView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" /> 
</LinearLayout> 

potuto essere gonfiati nel vostro adattatore come così:

@Override 
public View getView(final int position, View convertView, ViewGroup parent) { 
    LinearLayout root = null; 
    ImageView editImageView; 

    if (convertView == null) { 
     LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     root = (LinearLayout)inflater.inflate(R.layout.item, null); 
    } else { 
     root = (LinearLayout)convertView; 
    } 
} 

Si può anche essere un po 'più intelligente al fine di sostenere un colpo di testa. Basta aggiungere un controllo se l'indice è la radice e gonfiare una vista diversa. Dal momento che l'intestazione è l'unica che è diversa, continuerai a sfruttare tutte le altre file riutilizzabili. Puoi persino pre-gonfiare e memorizzare l'intestazione e riutilizzarla per eliminare completamente l'inflazione.

+0

Grazie. Ma ho notato che il layout è "più complesso di una semplice lista", piuttosto che "troppo complesso" (lo stesso layout è semplice). Non avrei problemi a gonfiare il tutto. Il problema è che non vedo come potrei far funzionare il mio layout con le intestazioni su un 'ListView', considerando che ho elementi che stanno dietro l'elenco (l'immagine nel mio diagramma). Posso avere un'immagine allegata all'inizio di 'ListView' ma sotto gli elementi figli? – zeh

Problemi correlati