Autore Topic: [facile] Aggiornare ListView popolata da un cursor + download e parsing JSON  (Letto 12184 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
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 scaricare un file json da internet, leggerlo e parsarlo (trasformare la stringa grezza in un oggetto) e quindi popolare un database.
Successivamente al parsing, una listview verrà popolata in base ai dati presenti nel database.

Iniziamo con una dimostrazione degli oggetti nel json:


Quindi il flow dell'applicazione; Parte con lista vuota e db vuoto (viene svuotato la prima volta che si apre il db), dopodichè si avvia il thread di download, in seguito il parsing del file JSON recuperato e quindi, l'update della ListView come desiderato!



La procedura è molto semplice, per dettagli maggiori scaricatevi i sorgenti completi in allegato...
Dopo aver creato un main layout che presenta una TextView e una ListView (vedi tutorial di Qlimax: [medio] Creazione e utilizzo di un database SQLite - Android Developers Italia[/url]), creiamo un customLayout per gli elementi della listView:
Codice (XML): [Seleziona]
<LinearLayout xmlns:android="[url]http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent" android:layout_height="fill_parent"
        android:orientation="vertical" android:weightSum="10">
        <LinearLayout android:layout_height="0dp"
                android:layout_width="fill_parent" android:orientation="horizontal"
                android:layout_weight="2" android:weightSum="10">
                <TextView android:id="@+id/posText" android:text="Pos:"
                        android:layout_width="0dp" android:layout_height="fill_parent"
                        android:textSize="11dp" android:textStyle="bold"
                        android:layout_weight="2" android:textColor="#00FF00" />
                <TextView android:id="@+id/driverPos"
                        android:layout_height="fill_parent" android:layout_width="0dp"
                        android:textSize="10dp" android:layout_weight="8" android:textStyle="bold"
                        android:textColor="#FFFFFF" />
        </LinearLayout>
        <LinearLayout android:layout_height="0dp"
                android:layout_width="fill_parent" android:orientation="horizontal"
                android:layout_weight="2" android:weightSum="10">
                <TextView android:id="@+id/nameText" android:text="Nome:"
                        android:layout_width="0dp" android:layout_height="fill_parent"
                        android:textSize="11dp" android:textStyle="bold"
                        android:layout_weight="2" android:textColor="#00FF00">
                </TextView>
                <TextView android:id="@+id/driverName"
                        android:layout_height="fill_parent" android:layout_width="0dp"
                        android:textSize="10dp" android:layout_weight="8" android:textStyle="bold"
                        android:textColor="#FFFFFF">
                </TextView>
        </LinearLayout>
        <LinearLayout android:layout_height="0dp"
                android:layout_width="fill_parent" android:orientation="horizontal"
                android:layout_weight="2" android:weightSum="10">
                <TextView android:id="@+id/surnameText" android:text="Cognome:"
                        android:layout_width="0dp" android:layout_height="fill_parent"
                        android:textSize="11dp" android:textStyle="bold"
                        android:layout_weight="2" android:textColor="#00FF00">
                </TextView>
                <TextView android:id="@+id/driverSurname"
                        android:layout_height="fill_parent" android:layout_width="0dp"
                        android:textSize="10dp" android:layout_weight="8" android:textStyle="bold"
                        android:textColor="#FFFFFF">
                </TextView>
        </LinearLayout>
        <LinearLayout android:layout_height="0dp"
                android:layout_width="fill_parent" android:orientation="horizontal"
                android:layout_weight="2" android:weightSum="10">
                <TextView android:id="@+id/teamText" android:text="Team:"
                        android:layout_width="0dp" android:layout_height="fill_parent"
                        android:textSize="11dp" android:textStyle="bold"
                        android:layout_weight="2" android:textColor="#00FF00">
                </TextView>
                <TextView android:id="@+id/driverTeam"
                        android:layout_height="fill_parent" android:layout_width="0dp"
                        android:textSize="10dp" android:layout_weight="8" android:textStyle="bold"
                        android:textColor="#FFFFFF">
                </TextView>
        </LinearLayout>
        <LinearLayout android:layout_height="0dp"
                android:layout_width="fill_parent" android:orientation="horizontal"
                android:layout_weight="2" android:weightSum="10">
                <TextView android:id="@+id/pointsText" android:text="Punti:"
                        android:layout_width="0dp" android:layout_height="fill_parent"
                        android:textSize="11dp" android:textStyle="bold"
                        android:layout_weight="2" android:textColor="#00FF00">
                </TextView>
                <TextView android:id="@+id/driverPoints"
                        android:layout_height="fill_parent" android:layout_width="0dp"
                        android:textSize="10dp" android:layout_weight="8" android:textStyle="bold"
                        android:textColor="#FFFFFF">
                </TextView>
        </LinearLayout>
</LinearLayout>

Sembra molto complesso, ma in realtà è semplice. Quando vedete 0db, è un trucchetto utile per lasciare al framework la gestione delle dimensioni, va messo sulla dimensione di orientamento del parent (le due textView hanno width = 0dp poichè il loro LinearLayout è horizontal.
I Permessi da dare all'app:
Codice (XML): [Seleziona]
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
        <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

Di seguito, partiamo con la stesura dell'app...
Tralasciando la prima parte del codice dell'onCreate, che è uguale a quella documentata da Qlimax, passiamo all'avvio del thread di download:
Codice (Java): [Seleziona]
                       Cursor c = db.fetchPiloti();
                       startManagingCursor(c);
                        if (c.getCount() == 0) {
                        System.out.println("DOWNLOADING Drivers....");
                        DownloadThread t = new DownloadThread(handler);
                        pd = ProgressDialog.show(this, "Scaricamento dati..", "Scarico i piloti", true, false);
                        t.start();
                }
Si avvia il Thread di download e si mostra una progress bar indefinita e NON cancellabile che mostra il processo in esecuzione.
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() {
                Log.i("LVUpdate/DOWNLOAD Thread", " *** Avvio della procedura di download ***  ");
                Message message = new Message();
                byte[] buffer = new byte[1024]; // buffer store for the stream
                String read = "";
                try {
                        urlConnection = url.openConnection();
                        inputStream = urlConnection.getInputStream();
                        int current = 0;
                        while (((current = inputStream.read(buffer)) != -1)) {
                                String temp = new String(buffer, 0, current);
                                read += temp;
                        }
                        inputStream.close();
                } catch (IOException e) {
                        Log.e("LVUpdate/DOWNLOAD Callable", "Error During Input Stream close; " + e.getMessage());
                }
                try {
                        message.what = Variables.DOWNLOAD_FINISHED;
                        message.obj = read;
                        message.arg1 = Variables.NO_ERROR;
                } catch (Exception e) {
                        message.arg1 = Variables.DOWNLOAD_ERROR;
                }
                        handler.sendMessage(message);
        }

Arrivati a questo punto, è ora di gestire la stringa ricevuta e consegnarla al parser JSON, tutto questo all'interno dell'handler dichiarato all'interno dell'activity...
Codice (Java): [Seleziona]
@Override
                public void handleMessage(Message msg) {
                        Object obj = msg.obj;
                        switch (msg.what) {
                        case Variables.DOWNLOAD_FINISHED:
                                String json = (String) obj;
                                Log.d("MESSAGE HANDLER RESPONSE", "Got the string from thread, size is " + json.length());
                                switch (msg.arg1) {
                                case Variables.NO_ERROR:
                                        Log.d("DOWNLOAD FINISHED", "DOWNLOAD SUCCESFULLY COMPLETED!");
                                        showToast("Scaricamento Piloti eseguito con successo");
                                        FileManager.writeToSD(json, Variables.FILE_PILOTI, getApplicationContext());
                                        pd.dismiss();
                                        pd = ProgressDialog.show(ListViewActivity.this, "Salvataggio dati..", "Parsing json...", true, false);

                                        new ParsingThread(json, db, handler).start();
                                        break;
                                case Variables.DOWNLOAD_ERROR:
                                        Log.e("LVUpdate/UIActivity", "DOWNLOAD HAS RAISED AN ERROR");
                                        break;
                                }
                                break;
                        case Variables.PARSING_FINISHED:
                                switch (msg.arg1) {
                                case Variables.NO_ERROR:
                                        pd.dismiss();
                                        updateListView();
                                        break;
                                case Variables.DOWNLOAD_ERROR:
                                        Log.e("LVUpdate/UIActivity", "DOWNLOAD HAS RAISED AN ERROR");
                                        break;
                                }
                                break;
                        }
                }
Da come si può vedere, una volta ottenuto il JSON tramite Message.what, scriviamo tale json su file(writeToSD in realtà salva nel context e non nell'SD), dismettiamo la ProgressDialog di download e ne riavviamo una per il parsing, avviando il Thread di parsing (che salva anche su DB).
Tale thread una volta finito risponderà sempre a questo handler, il quale,dopo avere fatto il dismiss della ProgressDialog, richiama la funzione di updateListView, che ora vediamo in dettaglio:
Codice (Java): [Seleziona]
private void updateListView() {
                TextView titleTv = (TextView) findViewById(R.id.dbTv);
                db.open();
                c = db.fetchPiloti(); // query
                startManagingCursor(c);
                adapter.changeCursor(c);
                adapter.notifyDataSetChanged();
                int nPiloti = db.countRecords(Variables.PilotiMD.PILOTI_TABLE);
                titleTv.setText("Database F1Db\n\tTabella " + Variables.PilotiMD.PILOTI_TABLE + " , n° di Record: " + nPiloti + "\n");
                db.close();
        }

Questa funzione prima di tutto, riesegue il cursor per ottenere la lista degli elementi dal database, in seguito aggiorna il cursor per la listView,e  notifica il cambiamento di dati,in modo da notificare alla listview la necessità di essere ridisegnata.
In seguito, aggiorna la textView in cima con la quantità di elementi nel database.
Vanno fatte due considerazioni:
- Il cursor si potrebbe aggiornare semplicemente con c.requery(), ma questa funzione va solo e soltanto se il database non è stato chiuso. Se db viene chiuso, allora il cursor perde la referenza e quindi va rieseguito e non si può fare la requery, ecco perchè nel codice qui, viene fatto di nuovo il fetchPiloti().
La listView va aggiornata anche una volta messa in pausa l'app e riaperta, se vi guardate i sorgenti, ho inserito il codice anche nella onResume().
l'ultima cosa che volevo mostrarvi e che può servirvi, è come ordinare degli elementi in base ad un campo int, tramite query su database:
Codice: [Seleziona]
"SELECT _id,(SELECT COUNT(*) FROM piloti p2 WHERE p2.points >= p.points) AS rownumber, nome,cognome,points,team FROM PILOTI p ORDER BY POINTS DESC"Tale query mostra id, posizione, nome, cognome, punti e team di un pilota, ordinandoli per punti (da chi ne ha di più a chi ne ha meno).
Si basa sul count, che viene fatto sul numero di piloti che hanno almeno i punti del pilota attuale (il primo quindi avrà 1, se stesso, il secondo ha se stesso ed il primo, quindi due, e così via).

Spero di aver fatto cosa gradita a postare il tutorial, aspetto commenti, domande e discussioni costruttive!

Bibliografia:
« Ultima modifica: 15 Novembre 2010, 22:05:26 CET da Nicola_D »
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 JD

  • Amministratore
  • Utente storico
  • *****
  • Post: 1600
  • Respect: +232
    • leinardi
    • Mostra profilo
  • Dispositivo Android:
    LG Nexus 5
  • Sistema operativo:
    L'ultima Ubuntu
Re:[facile] Aggiornare ListView popolata da un cursor + download e parsing JSON
« Risposta #1 il: 16 Novembre 2010, 13:27:15 CET »
0
Purtroppo non ho ancora finito di sistemare il PC nuovo e quindi non posso provare il tutorial, ma ti faccio comunque i complimenti perché mi sembra veramente ben realizzato :)
È stata trovata una soluzione al tuo problema?
Evidenzia il post più utile premendo . È un ottimo modo per ringraziare chi ti ha aiutato ;).
E se hai aperto tu il thread marcalo come risolto cliccando !

Offline Vytek

  • Translate Team
  • Utente junior
  • **
  • Post: 125
  • Respect: +6
    • Mostra profilo
  • Dispositivo Android:
    Samsung S5
  • Sistema operativo:
    Windows 8.1
Re:[facile] Aggiornare ListView popolata da un cursor + download e parsing JSON
« Risposta #2 il: 16 Novembre 2010, 13:29:51 CET »
0
Complimenti veramente! Scritto benissimo e molto chiaro!

Un saluto e grazie di tutto...

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] Aggiornare ListView popolata da un cursor + download e parsing JSON
« Risposta #3 il: 16 Novembre 2010, 13:33:44 CET »
0
Vi Ringrazio per i complimenti e non nego che mi piacerebbe scriverne piu di uno, peccato che in questo periodo il tempo è veramente poco...
Da dicembre sono sotto con la tesi, per la quale svilupperò su samsung galaxy tab un'applicazione di "social networking scientifico", quindi avrò modo di fare tante cose,e magari di creare qualche tutorial interessante...
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 francle81

  • Nuovo arrivato
  • *
  • Post: 3
  • Respect: 0
    • Mostra profilo
Re:[facile] Aggiornare ListView popolata da un cursor + download e parsing JSON
« Risposta #4 il: 20 Gennaio 2011, 12:02:25 CET »
0
Ammetto di essere entrato da poco nel mondo android...
ma lo scaricamento dei piloti quando avviene?e fisicamente quella tabella dov'è?

Grazie

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] Aggiornare ListView popolata da un cursor + download e parsing JSON
« Risposta #5 il: 20 Gennaio 2011, 14:05:20 CET »
0
Ammetto di essere entrato da poco nel mondo android...
ma lo scaricamento dei piloti quando avviene?e fisicamente quella tabella dov'è?

Grazie
lo scaricamento dei piloti avviene al momento della chiama della funzione di download.
per quella tabella cosa intendi? quella foto o la tabella nel database?
la foto è uno screen di un sito che riordina i jsons, la tabella invece viene creata dal dbHelper all'avvio!
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 francle81

  • Nuovo arrivato
  • *
  • Post: 3
  • Respect: 0
    • Mostra profilo
Re:[facile] Aggiornare ListView popolata da un cursor + download e parsing JSON
« Risposta #6 il: 21 Gennaio 2011, 09:23:02 CET »
0
è possibile che a me nn scarichi nulla perchè non riesce a trovare il file json su http://pastebin.ca/raw/1989140?

Offline Ansem

  • Utente junior
  • **
  • Post: 107
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    HTC HD2
  • Sistema operativo:
    4.0.4
0
scusate la mia ignoranza,ma qualcuno mi potrebbe spiegare la classe try/catch?
Io non ho capito cosa devo scrivere per dire cosa fare in base alla risposta che mi torna :(
Nel mio caso in particolare mi dovrebbero tornare come risposte si o no,oltre ovviamente all'eventualità che non ritorni niente. in quel caso cosa dovrei scrivere?

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
0
scusate la mia ignoranza,ma qualcuno mi potrebbe spiegare la classe try/catch?
Io non ho capito cosa devo scrivere per dire cosa fare in base alla risposta che mi torna :(
Nel mio caso in particolare mi dovrebbero tornare come risposte si o no,oltre ovviamente all'eventualità che non ritorni niente. in quel caso cosa dovrei scrivere?
se non sai cos'è il try catch, devi fare un passo indietro e studiare un po la programmazione, il try catch non è neanche specifico di java o android...
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
0
se non sai cos'è il try catch, devi fare un passo indietro e studiare un po la programmazione, il try catch non è neanche specifico di java o android...
mi potresti allora dire su che linguaggio cercare informazioni? io provengo da pascal/delphi e questo comando non l'ho mai visto :(

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] Aggiornare ListView popolata da un cursor + download e parsing JSON
« Risposta #10 il: 15 Marzo 2012, 17:01:36 CET »
0
anche c# c++ hanno try catch!
devi impararti un po il java, ci sono tanti siti/libri free per java
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 ALEX88-ANDR0!D

  • Utente normale
  • ***
  • Post: 173
  • The Special One
  • Respect: +13
    • Google+
    • droidev88
    • Mostra profilo
  • Dispositivo Android:
    HTC DESIRE HD
  • Sistema operativo:
    WINDOWS 7
Re:[facile] Aggiornare ListView popolata da un cursor + download e parsing JSON
« Risposta #11 il: 20 Giugno 2012, 12:47:41 CEST »
0
è possibile che a me nn scarichi nulla perchè non riesce a trovare il file json su http://pastebin.ca/raw/1989140?

ciao , anche a me non riesce a scaricare nulla ... volevo sapere , è possibile inserire nel database uri clicccabili , vi spiego brevemente , ho un progetto da realizzare in cui devo elencare diversi corsi che man mano possono essere aggiunti o tolti e pensavo di creare una tabella in sql con i dati "nome corso , descrizione breve , costo e un link che rimanda alla pagina web del corso con maggiori info , semai apro un altro topic per addentrarmi nella problematica ,  ps: ringrazio per il codice Nicola_D  :-)
È stata trovata una soluzione al tuo problema?
Evidenzia il post più utile premendo . È un ottimo modo per ringraziare chi ti ha aiutato ;).
E se hai aperto tu il thread marcalo come risolto cliccando !

Offline barmo

  • Nuovo arrivato
  • *
  • Post: 10
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    SGS CyanogenMod 9 RC2
  • Sistema operativo:
    Windows 7
Re:[facile] Aggiornare ListView popolata da un cursor + download e parsing JSON
« Risposta #12 il: 24 Luglio 2012, 21:56:29 CEST »
0
Ottima guida! Molto utile.
Confermo che non si riesce a scaricare il JSON dall'URL contenuto nel progetto.
Sarebbe possibile magari inserire un esempio di un JSON relativo a questo esempio?
Ho caricato su un mio spazio il file esempio.json contenente:
[{
    "id": "1",
    "name": "Nome",
    "surname": "Cognome",
   "points": "32",
   "team": "MyTeam"
}]
Lo scaricamento viene eseguito correttamente ma nel LogCat ottengo l'errore:
"07-24 22:34:26.675: W/System.err(5697): org.json.JSONException: Value [{"id":"1","surname":"Cognome","team":"MyTeam","points":"32","name":"Nome"}] of type org.json.JSONArray cannot be converted to JSONObject".
Suggerimenti?
Grazie
Buona serata,
barmo
« Ultima modifica: 24 Luglio 2012, 22:36:23 CEST da barmo »

Offline barmo

  • Nuovo arrivato
  • *
  • Post: 10
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    SGS CyanogenMod 9 RC2
  • Sistema operativo:
    Windows 7
Re:[facile] Aggiornare ListView popolata da un cursor + download e parsing JSON
« Risposta #13 il: 24 Luglio 2012, 22:49:31 CEST »
0
Ok, ci sono riuscito.  ;-)
A chi dovesse servire, la formattazione del file JSON deve seguire la seguente struttura:
{ "count": "1",
"results": [{
    "id": "1",
    "name": "Nome",
    "surname": "Cognome",
   "points": "32",
   "team": "MyTeam"
   }]
}
Buona serata a tutti e grazie ancora per la guida!

Offline whiteCloud

  • Nuovo arrivato
  • *
  • Post: 2
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    samsung galaxy s3
Re:[facile] Aggiornare ListView popolata da un cursor + download e parsing JSON
« Risposta #14 il: 03 Novembre 2012, 16:12:46 CET »
0
Ciao! La tua guida mi sembra ottima!Purtroppo sono nuovo della programmazione Android ed il file allegato mi aiuterebbe molto a comprendere la guida,ma non riesco a trovarlo :( E' ancora disponibile?
Grazie millee
Ciao :)