Autore Topic: AsyncTask e onPostExecute  (Letto 2030 volte)

Offline davraf

  • Nuovo arrivato
  • *
  • Post: 9
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    GT-I9001
  • Sistema operativo:
    Android 2.3.6, Kernel 2.6.35.7
AsyncTask e onPostExecute
« il: 16 Aprile 2013, 17:37:16 CEST »
0
Ciao,
sono neofita con Android e Java ma googlando e cercando qui sono riuscito a mettere in piedi un AsyncTask che fa il suo dovere ma stranamente non passa per onPostExecute e io non riesco a capire dove sbaglio.
Problema: leggo da un webservice una serie di dati, li elaboro e li mostro.
Implementazione: chiamo il webservice da un AsyncTask che mi restituirà un SoapObject ma intanto nella onPreExecute apro una dialog che chiudo nella onPostExecute.
Il risultato che ottengo è che mi viene restituito l'oggetto soap riempito e DOPO che l'ho lavorato mi appare la progressdialog che rimane li col suo cerchio che gira.
Da quanto ho letto invece mi aspettavo la show della progress, la lettura dei dati, la chiusura della progress, la visualizzazione dei dati

questa è la mia classe AsyncTask
Codice: [Seleziona]
public class Ksoap2AsyncTask extends AsyncTask<String, Void, SoapObject> {
        private ProgressDialog dialog = new ProgressDialog(MainActivity.this);

        protected void onPreExecute() {
            dialog.setMessage("Connecting...");
            dialog.show();
        }

                @Override
                protected SoapObject doInBackground(String... args) {
                        dialog.setMessage("downloading...");
                        CallSoap cs=new CallSoap();
                        SoapObject soap = (SoapObject)cs.CallasObject();
                return soap;
                }

        protected void onPostExecute(Void v) {
                dialog.setMessage("End...");
                if (dialog.isShowing()) {
                dialog.dismiss();
            }
        }
    }

e questa è la chiamata
Codice: [Seleziona]
Ksoap2AsyncTask tsk = new Ksoap2AsyncTask();
SoapObject soap = tsk.execute("").get();
Integer quanti = soap.getPropertyCount();

for(int i=0;i<soap.getPropertyCount();i++)
{.......elaboro in una lista

Offline rs94

  • Utente normale
  • ***
  • Post: 227
  • Respect: +21
    • Mostra profilo
  • Dispositivo Android:
    Sony Ericsson Xperia Arc S
  • Sistema operativo:
    Windows 8
Re:AsyncTask e onPostExecute
« Risposta #1 il: 16 Aprile 2013, 20:10:59 CEST »
0
Potrebbe essere una sciocchezza... ma non mancano gli @Override su onpreexcute e su onpostexecute?
L'unica certezza è il dubbio.
Dubitare di se stessi è il primo segno di intelligenza.

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:AsyncTask e onPostExecute
« Risposta #2 il: 16 Aprile 2013, 20:29:16 CEST »
0
Il modo in cui usi AsyncTask è in un certo senso sbagliato, lo stai usando in modo "bloccante", cioè lo istanzi e lo avii, ma blocchi l'esecuzione del thread corrente finchè la get() non ritorna, vanificando il concetto di esecuzione in thread separato.

Codice (Java): [Seleziona]
Ksoap2AsyncTask tsk = new Ksoap2AsyncTask();
SoapObject soap = tsk.execute("").get();

Usualmente si avvia l'esecuzione e di fa in modo che sia la OnPostExecute a gestire la conclusione. Prova a togliere il get() e vedi se te la esegue.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline davraf

  • Nuovo arrivato
  • *
  • Post: 9
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    GT-I9001
  • Sistema operativo:
    Android 2.3.6, Kernel 2.6.35.7
Re:AsyncTask e onPostExecute
« Risposta #3 il: 17 Aprile 2013, 12:37:52 CEST »
0
se tolgo la get però non riesce a restituirmi l'oggetto, intellisence mi dice che non riesce a convertire il risultato in un SoapObject. ho provato comunque modificando un momento il codice per ignorare il risultato ma non cambia, esegue il codice correttamente e alla fine apre la dialog. ho attivato il debug ma non passa proprio per la onPostExecute.

so che è un controsenso bloccare il thread principale con un thread secondario ma ho trovato questo come esempio. il problema di fondo era che non si chiama un webservice dal thread principale perchè da android 4 si blocca l'applicazione. infatti mentre sul mio galaxy splus con gingerbread  va sempre, sul galaxy note 10.1 con Jelly Bean non andava fino a quando non ho implementato il thread.

sono aperto ad altre soluzioni.

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:AsyncTask e onPostExecute
« Risposta #4 il: 17 Aprile 2013, 13:43:39 CEST »
0
sono aperto ad altre soluzioni.

La soluzione è usare AsyncTask nel modo usuale, come ti avevo accennato sopra, senza farsi restituire l'oggetto dall'avvio dell'asynctask, ma facendo in modo sia la OnPostExecute ad inviarlo.

Che poi non è altro che la programmazione multi-thread classica.

Citazione
Usualmente si avvia l'esecuzione e di fa in modo che sia la OnPostExecute a gestire la conclusione.

In questo mio vecchio tutorial
[facile] HttpBookSearch: AsyncTask, HttpClient, XML parsing, ProgressDialog - Android Developers Italia
puoi vedere cosa intendo con la frase che ho scritto sopra:
- Lancio un AsyncTask per fare una richiesta http in modo non bloccante : task.execute(editIsbn.getText().toString());
- Nell'asynctask ricevo il risultato XML : result = client.execute(get,responseHandler);
- Nell'asynctask faccio il parsing XML : Document doc = db.parse(new InputSource(new StringReader(result)));
- Nella OnPostExecute comunico i dati all'activity, nel mio caso scrivendo a video : txtTitle.setText("TITLE\n"+title);
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline davraf

  • Nuovo arrivato
  • *
  • Post: 9
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    GT-I9001
  • Sistema operativo:
    Android 2.3.6, Kernel 2.6.35.7
Re:AsyncTask e onPostExecute
« Risposta #5 il: 18 Aprile 2013, 18:01:04 CEST »
0
ok, ragionando su quello che ha detto ilseric, dando retta a te, bradipao e tornando alle origini ho raggiunto un primo traguardo, quello di avere i metodi di AsyncTask funzionanti.
Quando si fa copia/incolla da internet senza avere chiaro quello che leggi può dare un problema, infatti la chiave è stata la mancanza di @Override sul metodo onPostExecute.
Il metodo era sbagliato, infatti affidandomi ad ADV ho overridato il metodo giusto. In uno spazio bianco della pagina ho fatto dasto destro, Source, Override/Implement Methods ed intellisence mi ha generato il metodo con le firme corrette.
Allora ho voluto fare mente locale e riscrivere una classe con tutti i parametri vuoti, che non fa praticamente niente ma che funziona.
Da qui proseguirò perchè le cose si stanno facendo divertenti...

Codice (Java): [Seleziona]
        /**
     *
     * @author davide.raffagli
     * leggo dal webservice l'elenco dei ristoranti
     * e li carico nella View
     */

        private class LocaliReadAsync extends AsyncTask<Void, Void, Void>{
                //dichiarazione degli oggetti privati alla classe
                private ProgressDialog dialog = new ProgressDialog(MainActivity.this);
               
                @Override
                protected void onPreExecute() {
                        // TODO Auto-generated method stub
                        super.onPreExecute();
                        dialog.setMessage("inizio...");
                        dialog.show();
                }

                @Override
                protected Void doInBackground(Void... params) {
                        // TODO Auto-generated method stub
                        dialog.setMessage("downloading...");
                        WSServiceManager cs = new WSServiceManager();
                        SoapObject soap = (SoapObject) cs.localiReadAll();
                        return null;
                }

                @Override
                protected void onProgressUpdate(Void... values) {
                        // TODO Auto-generated method stub
                        super.onProgressUpdate(values);
                }
               
                @Override
                protected void onPostExecute(Void result) {
                        // TODO Auto-generated method stub
                        super.onPostExecute(result);
                        dialog.setMessage("populating...");

                        if (dialog.isShowing()) {
                                dialog.dismiss();
                        }
                }

        }

Offline GabMarioPower

  • Moderatore globale
  • Utente senior
  • *****
  • Post: 606
  • Respect: +152
    • Github
    • Google+
    • gabrielemariotti
    • GabMarioPower
    • Mostra profilo
  • Play Store ID:
    GAB+MARIO+DEV
  • Sistema operativo:
    Ubuntu 14.04 , Win 10
Re:AsyncTask e onPostExecute
« Risposta #6 il: 19 Aprile 2013, 10:27:29 CEST »
+1
Ti hanno già risposto in diversi.
Al di là del fatto che possa o meno funzionare (a volte le cose funzionano anche se fatte male), mi permetto di sottolineare alcuni aspetti che invece sono importanti.

L'Async Task a dispetto del nome, ha alcuni metodi che vengono eseguiti nel main Thread.
Questo significa che blocca la videata principale, cosa assolutamente da evitare.

Il solo metodo doInBackground è eseguito effettivamente in un thread separato.
Gli altri metodi, onPreExecute(), onPostExecute(), onProgressUpdate sono invece eseguiti nel Main Thread.
Puoi facilmente vederlo tu stesso utilizzando il debug di eclipse. (mi permetto di linkare una mia immagine... )



Questo nel concreto, si traduce nel fatto che la chiamata al web service va fatta nel metodo doInBackground.

Cosi come ti è stato suggerito, la procedura da seguire è questa qui sotto.
Citazione
- Lancio un AsyncTask per fare una richiesta http in modo non bloccante : task.execute(editIsbn.getText().toString());
- Nell'asynctask ricevo il risultato XML : result = client.execute(get,responseHandler);
- Nell'asynctask faccio il parsing XML : Document doc = db.parse(new InputSource(new StringReader(result)));
- Nella OnPostExecute comunico i dati all'activity, nel mio caso scrivendo a video : txtTitle.setText("TITLE\n"+title);
Precisando che anche la parserizzazione ed elaborazione è bene farla nello stesso metodo doInBackground, lasciando al onPostExecute (che è sincronizzato con la UI) il solo onere di aggiornare la videata con i dati già pronti.

Questo codice invece NON va bene.
Perchè blocca di fatto l'esecuzione sulla UI principale.
Citazione
Codice (Java): [Seleziona]
        Ksoap2AsyncTask tsk = new Ksoap2AsyncTask();
        SoapObject soap = tsk.execute("").get();

Ultima cosa, non meno importante secondo me è la Dialog.
Le dialog andrebbe sempre più evitate....
Non è un problema di codice, ma di linee guida Android e di impatto sull'utente.
Informazioni chiamate in-line e non bloccanti sull'utente sono sempre preferibili.

Mi permetto di linkare un post molto significativo fatto da uno degli sviluppatori Android di Google ( lo statuto non so se lo permette....)
https://plus.google.com/+RomanNurik/posts/eSCfnyTzFUx


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:AsyncTask e onPostExecute
« Risposta #7 il: 19 Aprile 2013, 10:34:54 CEST »
0

Mi permetto di linkare un post molto significativo fatto da uno degli sviluppatori Android di Google ( lo statuto non so se lo permette....)
https://plus.google.com/+RomanNurik/posts/eSCfnyTzFUx


Ogni informazione utile (soprattutto se ben citata, documentata e proveniente da fonti attendibili) va citata sul forum. Quello che non è permesso è la pubblicità o i link a forum direttamente concorrenti.
RomanNurik direi che non è un concorrente, ma una fonte d'ispirazione (qualcuno ha detto Dash Clock?)
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 davraf

  • Nuovo arrivato
  • *
  • Post: 9
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    GT-I9001
  • Sistema operativo:
    Android 2.3.6, Kernel 2.6.35.7
Re:AsyncTask e onPostExecute
« Risposta #8 il: 23 Aprile 2013, 10:33:04 CEST »
0
grazie a tutti per le indicazioni, tra i link e il libro che mi sto leggendo credo di aver capito:
la classe AsyncTask è una classe che esiste nello stesso task della Activity. A differenza di altri ambienti è la classe stessa che si occupa di creare ed eseguire un task separato che noi vediamo nel metodo doInBackground. Sempre la stessa classe si occupa di impostare tutti i delegate necessari per comunicare con l'Activity. Per questo è importante non bloccare l'esecuzione della Activity, per poter rispondere agli eventi onProgressUpdate e onPostExecute. alla luce di ciò ho modificato la mia classe

Codice (Java): [Seleziona]
        private class LocaliReadAsync extends AsyncTask<Void, Integer, ArrayList<Ristorante>>{
                //dichiaro la collezione che ospiterà i ristoranti in memoria
                ArrayList<Ristorante> list = new ArrayList<Ristorante>();
               
                @Override
                protected void onPreExecute() {
                        // TODO Auto-generated method stub
                        super.onPreExecute();
                        progress.setVisibility(View.VISIBLE); //rendo visibile la progress standard
                }

                @Override
                protected ArrayList<Ristorante> doInBackground(Void... params) {
                        // TODO Auto-generated method stub
                        WSServiceManager cs = new WSServiceManager();
                        SoapObject soap = (SoapObject) cs.localiReadAll();
                       
                        // giro per i ristoranti e li traduco nelle relative classi
                        for (Integer i = 0; i < soap.getPropertyCount(); i++) {
                                SoapObject soapResult = (SoapObject) soap.getProperty(i);
                                Ristorante rist = new Ristorante();
                                //..... riempio la classe.....
                                list.add(rist); //li colleziono
                                publishProgress(i); //mi invio il contatore per avere un'idea di avanzamento
                        }

                        return list;
                }

                protected void onProgressUpdate(Integer... values) {
                        // TODO Auto-generated method stub
                        super.onProgressUpdate(values);
                        txMsg.setText(Integer.toBinaryString(values[0])); //giusto per vedere se l'evento viene generato
                }
               
                @Override
                protected void onPostExecute(ArrayList<Ristorante> result) {
                        // TODO Auto-generated method stub
                        super.onPostExecute(result);
                       
                        // istanzio la classe riga per la lista
                        RistorantiAdapter ristorantiAdapter = new RistorantiAdapter(MainActivity.this, result);
                        lvRistoranti.setAdapter(ristorantiAdapter);
                        progress.setVisibility(View.GONE);
                }

        }

c'è ancora da lavorare per ottimizzare il tutto ma credo che l'obbiettivo sia centrato, quindi segno il post come risolto.