Autore Topic: [facile] Endless List, Una lista senza fine  (Letto 5921 volte)

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
[facile] Endless List, Una lista senza fine
« il: 15 Giugno 2011, 17:50:03 CEST »
+6
Livello di difficoltà: facile
Target SDK: 7
Min SDK: 5
Link al file compresso del progetto eclipse: file in allegato

Ecco qui un semplice tutorial che vi mostra come creare una listView con pochi elementi all'inizio, ma che crescono in caso di bisogno, nello specifico, quando si arriva alla fine della lista...
Il progetto in allegato sfrutta uno script gentilmente offerto dal nostro Ricky, che genera un file json, il quale viene parsato e utilizzato dall'adapter della list view.
In caso di bisogno di aggiunta di elementi, abbiamo lo script che genera altri elementi, a partire dall'ultimo che gli inviamo!
Conoscenze richieste?
JSON (Parsing e Struttura)
Handler (Thread & Message)
List View (conoscenze base)
Se non avete queste conoscenze, spolveratevele o imparatele, questo tutorial non vi spiegherà queste cose :D
Il json utilizzato qui, è un oggetto che contiene un dato che ci indica se ci sono altri elementi, piu un'array di object, ogniuno formato da ID e Testo. Quindi l'esempio è molto semplice!

Quindi il flow dell'applicazione; Si parte con lista vuota, si scaricano i primi elementi e nel frattemo nella barra in alto abbiamo conferma del refresh in corso. Scaricati i primi dati, vengono aggiunti all'adapter, cosi da mostrarveli a schermo. Ora ci sono due casi:
-Altri elementi disponibili
-Nessun altro elemento disponibile

Nel primo caso, è sufficiente scorrere in basso la lista, fino a che non comparirà una view di caricamento. Una volta scaricati i nuovi dati, la view sparirà e verrà sostituita dai nuovi elementi.
Nel secondo caso invece, potete cliccare su refresh per generare una nuova lista, che magari in questo caso vi lascia scaricare altri elementi!



La procedura è molto semplice, per dettagli maggiori scaricatevi i sorgenti completi in allegato...
Dopo aver creato un main layout che presenta un linearLayout per la barra in alto, ed una ListView, creiamo un customLayout per gli elementi della listView:
Codice (XML): [Seleziona]
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:padding="5dp">
   <TextView
     android:id="@+id/feed_id"
     android:text="ID #"
     android:layout_alignParentTop="true"
     android:layout_alignWithParentIfMissing="true"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:lines="1"
     android:ellipsize="marquee" />
   <TextView
     android:text="Description #"
     android:id="@+id/feed_description"
     android:layout_below="@id/feed_id"
     android:layout_width="fill_parent"
     android:layout_gravity="center_vertical"
     android:layout_height="wrap_content"
     android:ellipsize="marquee"
     android:singleLine="true" />
</RelativeLayout>
Aggiungiamo anche il layout del footer, ovvero la view mostrata in fase di aggiornamento:
Codice (XML): [Seleziona]
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:paddingTop="10dp"
  android:paddingBottom="10dp"
  android:id="@+id/loadingMore"
  android:orientation="horizontal"
  android:layout_height="wrap_content"
  android:layout_width="fill_parent"
  android:gravity="center_horizontal"
  android:visibility="visible">
   <TextView
     android:text="Loading more..."
     android:layout_gravity="center_vertical"
     android:layout_height="wrap_content"
     android:layout_width="wrap_content" />
   <ProgressBar
     android:id="@+id/progressBar1"
     android:layout_marginLeft="10dp"
     android:layout_height="32dip"
     android:layout_width="32dip" />
</LinearLayout>

Il Permesso da dare all'app:
Codice (XML): [Seleziona]
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
E quindi, il codice!
Tralasciando la prima parte del codice dell'onCreate, che è un semplice inflating di view, passiamo alla parte interessante:
Codice (Java): [Seleziona]
                       //Creiamo l'adapter, aggiungiamo la footerView e poi la togliamo (va aggiunta prima di settare l'adapter, a causa di come funziona il list adapter
                adapter = new FeedsListAdapter(getApplicationContext(), feeds);
                getListView().addFooterView(loading);
                setListAdapter(adapter);
                //Eliminiamo il footer, perchè al momento non deve essere visualizzato, e dopo aver settato uno scroll listener sulla lista, avviamo il download dei dati.
                getListView().removeFooterView(loading);
                getListView().setOnScrollListener(this);
                new DownloadThread(url, mHandler, 1).start();
                mSyncing = true;
                setRefreshViews();
Set refresh view è un metodo che mostra o nasconde la progress bar durante il refresh.

Si avvia quindi il Thread di download, che non fa altro che scaricare la stringa JSON e parsarla, creando un'arraylist di oggetti Feeds (vedi i sorgenti).
Il processo, non fa altro che scaricare il raw dall'url messo a disposizione e restituirlo come object nell'handler passato in creazione del thread:
Codice (Java): [Seleziona]
public void run() {
String read = "";
                try {
                        read = useHttpGet(url);
                        parseFeeds(read);
                        Log.d(EndlessList.TAG, "Feeds ottenuti dalla stringa JSON");   
                        //Mandiamo un messaggio alla main activity, assegnando come what l'operazione che stiamo facendo (refresh o update),
                        message.what = mRefresh;
                        message.obj = feeds; //come object inseriamo i feeds scaricati
                        message.arg1 = 1;//come arg1 mettiamo 1, per indicare che l'operazione ha avuto successo.
                        message.arg2 = (endIsReached) ? 1 : 0;//Arg2 ci dirà se la fine della lista è raggiunta o meno
                } catch (Exception e) {
                        //... Gestire l'errore, vedi i sorgenti completi
                }
                handler.sendMessage(message);

Arrivati a questo punto, è ora di prendere i dati e darli in pasto all'adapter... Di seguito il metodo di gestione messaggi dell'handler
Codice (Java): [Seleziona]
switch (msg.what) {
                                case 1://Refresh
                                        switch (msg.arg1) {
                                                case 1://Download & Parsing ok, ricarichiamo la lista, risettando i dati ed il valore che indica se la lista è finita
                                                        feeds = (ArrayList<Feed>) msg.obj;
                                                        mSyncing = false;
                                                        int endReached = msg.arg2;
                                                        mEndIsReached = (endReached == 1) ? true : false;
                                                        refreshWholeList();
                                                        break;
                                                case -1://Errore durante il download, non aggiorniamo nessun dato
                                                        Log.e(TAG, "Download or parsing error");
                                                        mSyncing = false;
                                                        setRefreshViews();
                                                        break;
                                        }
                                        break;
                                case 2://Update
                                        switch (msg.arg1) {
                                                case 1://Download & Parsing ok, ricarichiamo la lista, aggiungiendo di dati scaricati in coda a quelli gia presenti
//aggiornamo anche il valore che indica se la lista è finita
                                                        feeds.addAll((ArrayList<Feed>) msg.obj);
                                                        mSyncing = false;
                                                        int endReached = msg.arg2;
                                                        mEndIsReached = (endReached == 1) ? true : false;
                                                        refreshUpdatedList();
                                                        break;
                                                case -1://Errore durante il download, non aggiorniamo nessun dato, ma togliamo il footer
                                                        Log.e(TAG, "Download or parsing error");
                                                        mSyncing = false;
                                                        getListView().removeFooterView(loading);
                                                        setRefreshViews();
                                                        break;
                                        }
                                        break;
                        }


Ora Vi chiederete, bello, ma il succo dove sta? come faccio a far caricare altri elementi quando arrivo in fondo alla lista? E qui arriva lo scrollListener, che si porta dietro un metodo che ci aiuta:
Codice (Java): [Seleziona]
public void onScroll(AbsListView view, int firstVisible, int visibleCount, int totalCount) {
//Se il primo elemento che vediamo (indice) sommato al numero di elementi visibili è uguale o maggiore al numero di elementi totali, allora siamo in fondo alla lista!
                boolean loadMore = firstVisible + visibleCount >= totalCount;
//Quindi, se siamo in fondo alla lista, non siamo gia in fase di sincronizzazione, e la fine della lista non è stata raggiunta (questo dipende dalla risposta JSON del server)
                if (loadMore && (totalCount > 0) && !mSyncing && !mEndIsReached) {
//Allora carichiamo altri elementi!
                        loadMoreComments();
                }
        }
Cosa fa loadMoreComments()? semplice, imposta la view del footer e richiama il thread di download e parsing, passandogli l'url apposito per l'update!
Codice (Java): [Seleziona]
public void loadMoreComments() {
                long lastFeedId = 0;
//Prendiamo l'id dell'ultimo elemento in lista
                if (feeds.size() > 0) lastFeedId = feeds.get(feeds.size() - 1).getId();
//Se non stiamo sincronizzando e ci sono ancora elementi da scaricare
                if (!mSyncing && !mEndIsReached) {
//Impostiamo la footerView
                        getListView().addFooterView(loading);
//Impostiamo l'url (vedi in basso)
                        String url2refresh = String.format(urlupd, lastFeedId);
//Avviamo il thread per l'update!
                        new DownloadThread(url2refresh, mHandler, 2).start();
                        mSyncing = true;
                }
        }

Cosa vi manca a tutto il tuorial? Ah si, i link di esempio usati nel progetto:
Codice (Java): [Seleziona]
private String url = "http://anddev-rest.heroku.com/resources";
        private String urlupd = "http://anddev-rest.heroku.com/resources/%d";
Il primo è il link per scaricare i dati "dall'inizio" il secondo invece, sostituendo l'id dell'ultimo elemento (come visto sopra) al posto di %d, otteniamo i 10 elementi successivi!

Questa è una "feature" che mi serviva nel progetto fatto qualche mese fa, mi son sempre ripromesso di postare un tutorial, ma non avevo uno script che generasse i dati al volo, con l'arrivo di quello di Ricky, ecco il tutorial! Quindi un grazie a lui, e a voi per aver seguito il tutorial!
Spero di aver fatto cosa gradita a postare il tutorial, aspetto commenti, domande e discussioni costruttive!

Bibliografia:
« Ultima modifica: 04 Dicembre 2011, 11:43:37 CET da JD »
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:Endless List, Una lista senza fine
« Risposta #1 il: 16 Giugno 2011, 11:14:25 CEST »
0
Dimenticavo:
Critiche e domande, son ben accette!
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline Kekko

  • Utente junior
  • **
  • Post: 88
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S2
  • Sistema operativo:
    W7
Re:Endless List, Una lista senza fine
« Risposta #2 il: 12 Ottobre 2011, 22:16:49 CEST »
0
Potrebbe essere usata per liste della spesa eccetera giusto? :D

Offline blackgin

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1387
  • Respect: +164
    • Google+
    • blackgins
    • blackginsoft
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Nexus
  • Sistema operativo:
    Mac OSX 10.8
Re:Endless List, Una lista senza fine
« Risposta #3 il: 12 Ottobre 2011, 22:20:34 CEST »
0
Potrebbe essere usata per liste della spesa eccetera giusto? :D
Spero che nessuno abbia una lista della spesa infinita  : O
Postate il LogCat LogCat LogCat LogCat LogCat

Offline Kekko

  • Utente junior
  • **
  • Post: 88
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S2
  • Sistema operativo:
    W7
Re:Endless List, Una lista senza fine
« Risposta #4 il: 13 Ottobre 2011, 19:14:10 CEST »
0
Ahaha :P
Intendevo per far si che quando siano finiti gli elementi della lista se ne creino altre :P Comunque poi magari apro un thread apposito :)

Offline Trigun

  • Utente normale
  • ***
  • Post: 183
  • Respect: +4
    • Mostra profilo
Re:[facile] Endless List, Una lista senza fine
« Risposta #5 il: 04 Marzo 2012, 20:46:09 CET »
0
si può fare in modo che la funzione di refresh parta subito dopo che l'activity viene creata e non per forza all'onscroll?

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:[facile] Endless List, Una lista senza fine
« Risposta #6 il: 04 Marzo 2012, 22:33:17 CET »
0
è sufficiente richiamare la funzione loadMoreComments();
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline Ansem

  • Utente junior
  • **
  • Post: 107
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    HTC HD2
  • Sistema operativo:
    4.0.4
Re:[facile] Endless List, Una lista senza fine
« Risposta #7 il: 06 Maggio 2012, 16:15:36 CEST »
0
raga io ho bisogno di fare questa cosa,però voglio che quando tappo uno degli elementi,parta un metodo che utilizzi i dati all'interno dell'elmento.
come posso fare? :(

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:[facile] Endless List, Una lista senza fine
« Risposta #8 il: 07 Maggio 2012, 09:21:38 CEST »
0
raga io ho bisogno di fare questa cosa,però voglio che quando tappo uno degli elementi,parta un metodo che utilizzi i dati all'interno dell'elmento.
come posso fare? :(
implementi il metodo di click degli item sulle listview
AdapterView.OnItemSelectedListener | Android Developers, android.view.View, int, long)

che ti da indietro la view parent (di solito la listView, la view che disegna l'elemento, la posizione nella lista e l'id. Se hai assegnato degli Id univoci alla lista dati che usi per renderizzare la listview, con quel long id ti cerchi l'elemento e lo usi!
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline Ansem

  • Utente junior
  • **
  • Post: 107
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    HTC HD2
  • Sistema operativo:
    4.0.4
Re:[facile] Endless List, Una lista senza fine
« Risposta #9 il: 11 Maggio 2012, 18:01:46 CEST »
0
mi sono letto la tua guida,e devo dire che complessivamente credo di aver capito XD
però alcune cose non mi sono chiare:
1)cos'è l'adapter?
2) parli di listview,però non l'ho vista nominata nel codice XML
3) visto che a me questa operazione basta farla alla creazione della pagina,mi basta far partire il metodo nell'oncreate giusto?

Offline tanux

  • Nuovo arrivato
  • *
  • Post: 2
  • Respect: 0
    • Mostra profilo
Re:[facile] Endless List, Una lista senza fine
« Risposta #10 il: 22 Luglio 2013, 15:02:03 CEST »
0
Salve, ho utilizzato questo topic per implementare l'Endless List. Ho un problema: quando carico i nuovi dati, viene effettuato un refresh della listview ritornando all'inizio della lista mentre vorrei che rimanesse nel punto in cui era arrivata prima dell'aggiornamento dati. Come posso fare?

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:[facile] Endless List, Una lista senza fine
« Risposta #11 il: 22 Luglio 2013, 19:03:57 CEST »
0
Salve, ho utilizzato questo topic per implementare l'Endless List. Ho un problema: quando carico i nuovi dati, viene effettuato un refresh della listview ritornando all'inizio della lista mentre vorrei che rimanesse nel punto in cui era arrivata prima dell'aggiornamento dati. Come posso fare?
Sei sicuro di aver seguito bene tutto? E di aver usato il last feedid?

Inviato dal mio Nexus 7 con Tapatalk 2
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia