Autore Topic: AsyncTask e timeout connessione  (Letto 2442 volte)

Offline sismouse

  • Utente junior
  • **
  • Post: 69
  • Respect: 0
    • Mostra profilo
AsyncTask e timeout connessione
« il: 28 Settembre 2014, 01:45:56 CEST »
0
Salve, nell'app che sto realizzando ho introdotto nell'activity principale un AsyncTask sottoforma di classe interna. Ebbene in questo AsyncTask mi sono preoccupato di gestire eventuali problemi o mancanza di connessione durante il download dei dati che avviene tramite il metodo connectAndCreateJsonArray() chiamato dal metodo doInBackground() dell'AsyncTask, solo che non sempre funziona correttamente. Potreste dare uno sguardo al codice e dirmi se sbaglio qualcosa o se c'è qualche parte che posso migliorare?

Codice: [Seleziona]
        private class DownloadDataFromServer extends AsyncTask<String, Integer, String> {
                ProgressDialog dialog;
                boolean connErr = false;
                boolean soErr = false;
         
                @Override
                protected void onPreExecute() {
                        dialog = new ProgressDialog(HomePage.this);
                        dialog.setIndeterminate(false);
                        dialog.setMax(100);
                        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                        dialog.setCancelable(false);
                        dialog.setTitle("Download");
                        dialog.setMessage("Aggiornamento dati in corso. Prego attendere...");
                        dialog.show();
         
                        super.onPreExecute();
                }
         
                @Override
                protected String doInBackground(String... urls) {
                        int count = 0;
                        int numUtenti = 0;
                        SQLiteDatabase localDB = db.getWritableDatabase();
                       
                        try {       
                                JSONArray UserJsonArray = connectAndCreateJsonArray(urls[0]);
                                                       
                                numUtenti = UserJsonArray.length();
                               
                                localDB.beginTransaction();
                               
                                for (int i = 0; i < numUtenti; i++) {
                                        JSONObject jObj = (JSONObject) UserJsonArray.getJSONObject(i);

                                        localDB.insert("users", null, getParsedUserEntry(jObj));
                                                       
                                        count++;
                                        publishProgress(count * 100 / numUtenti);
                                }

                                localDB.setTransactionSuccessful();
                               
                        } catch (IllegalStateException e) {
                                e.printStackTrace();                               
                        } catch (JSONException e) {
                                e.printStackTrace();
                                Log.e("Msg", "catch");
                        } finally {
                                localDB.endTransaction();
                        }

                        return numUtenti+"";
                }
               
                private JSONArray connectAndCreateJsonArray(String url) {
                        JSONArray jsonArray = new JSONArray();
                       
                        try {
                                HttpGet request = new HttpGet(url);
                                HttpParams httpParameters = new BasicHttpParams();
                               
                                // timeout until connection is established
                                int timeOutInMillis = 3000;
                                HttpConnectionParams.setConnectionTimeout(httpParameters, timeOutInMillis);
                               
                                // timeout until data is received
                                int socketTimeOutinMillis = 3000;
                                HttpConnectionParams.setSoTimeout(httpParameters, socketTimeOutinMillis);
                               
                                // create a client with the parameters
                                DefaultHttpClient client = new DefaultHttpClient(httpParameters);
                                HttpResponse response = client.execute(request);
                               
                                request.addHeader("Cache-Control", "no-cache");
                               
                                HttpEntity entity = response.getEntity();
                                InputStreamReader in = new InputStreamReader(entity.getContent());
                                BufferedReader reader = new BufferedReader(in);
                                StringBuilder stringBuilder = new StringBuilder();
                                String line = "";
                                while ((line = reader.readLine()) != null) {
                                        stringBuilder.append(line);
                                }
                               
                                jsonArray = new JSONArray(stringBuilder.toString());
                               
                        } catch (SocketTimeoutException e) {
                                connErr = true;
                                e.printStackTrace();
                        } catch (SocketException e) {
                                soErr = true;
                                e.printStackTrace();
                        } catch (IllegalStateException e) {
                                e.printStackTrace();                               
                        } catch (ClientProtocolException e) {
                                e.printStackTrace();
                        } catch (IOException e) {
                                e.printStackTrace();
                        } catch (JSONException e) {
                                e.printStackTrace();
                        }
                       
                        return jsonArray;
                }
               
                private ContentValues getParsedUserEntry(JSONObject entry) {
                        ContentValues values = new ContentValues();
                       
                        values.put("_id", entry.optString("id").toString());
                        values.put("nome", entry.optString("name").toString());
                        values.put("cognome", entry.optString("surname").toString());
                       
                        return values;
                }
               
                protected void onProgressUpdate(Integer... progress) {
                        dialog.setProgress(progress[0]);
                }
               
                @Override
                protected void onPostExecute(String result) {
                        Log.e("Connessione", connErr+"");
                        Log.e("Socket", soErr+"");
                        if (connErr || soErr) {
                            String msg = "Connessione lenta o non funzionante";
                                AlertDialog.Builder builder;
                            builder = new AlertDialog.Builder(HomePage.this);
                            builder.setCancelable(false);
                            builder.setTitle("Timeout connessione");
                            builder.setMessage(msg);
                           
                            builder.setPositiveButton("Riprova", new DialogInterface.OnClickListener(){
                        @Override
                        public void onClick(DialogInterface dialog, int which)
                        {
                            dialog.dismiss();
                            new DownloadDataFromServer().execute(new String[] { "http://www.miosito.org/getUsers.php" });
                        }
                    });
                   
                            builder.setNegativeButton("Esci", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                            finish();
                        }
                    });                   
                    AlertDialog dialog = builder.create();
                    dialog.show();
                        } else {
                            if (Integer.parseInt(result) <= 0) {
                                    Toast.makeText(getBaseContext(), "Scrittura database fallita!", Toast.LENGTH_SHORT).show();
                            } else {
                                    Toast.makeText(getBaseContext(), "Aggiornamento riuscito", Toast.LENGTH_SHORT).show();
                            }
                        }
                        dialog.dismiss();
                }
        }

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 timeout connessione
« Risposta #1 il: 28 Settembre 2014, 08:34:39 CEST »
+1
Per la richiesta di rete usa una libreria già fatta, come okhttp. Puoi usarla anche in modo sincrono dentro il tuo asynctask. Ha il vantaggio di gestire già internamente tutte le problematiche della connessione (timeout, non risposta, etc)
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline emaborsa

  • Utente normale
  • ***
  • Post: 274
  • Java Developer
  • Respect: +33
    • Google+
    • emaborsa
    • Mostra profilo
    • www.emaborsa.com
  • Dispositivo Android:
    Samsung Galaxy S2
  • Sistema operativo:
    Linux 10 - Win8.1 - Android 4.1.2
Re:AsyncTask e timeout connessione
« Risposta #2 il: 28 Settembre 2014, 11:32:14 CEST »
+1
... solo che non sempre funziona correttamente. Potreste dare uno sguardo al codice e dirmi se sbaglio qualcosa o se c'è qualche parte che posso migliorare?

Dovresti peró dirci esattamente il problema...

Offline sismouse

  • Utente junior
  • **
  • Post: 69
  • Respect: 0
    • Mostra profilo
Re:AsyncTask e timeout connessione
« Risposta #3 il: 28 Settembre 2014, 11:55:28 CEST »
0
Per la richiesta di rete usa una libreria già fatta, come okhttp. Puoi usarla anche in modo sincrono dentro il tuo asynctask. Ha il vantaggio di gestire già internamente tutte le problematiche della connessione (timeout, non risposta, etc)
Sebbene la tua idea sia molto valida, siccome sono davvero alle prime armi con lo sviluppo per Android, vorrei scrivere del codice nativo... e capire dove sbaglio o posso scriverlo meglio.
Riguardo il codice che ho postato, parzialmente scopiazzato da internet, sai dirmi se c'è qualcosa che non va?

Dovresti peró dirci esattamente il problema...
Ad esempio, quando provo l'app in un luogo dove c'è poco campo, la schermata di download resta a 0% e non va in timeout. Nel codice ho impostato 3 secondi di timeout sia alla connessione che al socket (tra l'altro non ho ben capito se questi timeout si sommano o meno), ma di fatto se la linea è scarsa la schermata resta a 0% per diversi secondi... prima che il download cominci e arrivi al 100%.
Invece altre volte, dopo tot secondi in cui non riesce a connettersi, mi dice direttamente Scrittura fallita tramite il toast.
Altre volte invece funziona e mi dice che la connessione è lenta (come impostato dall'AlertDialog).
C'è qualcosa che non va...

Anche tu, guardando il mio codice, trovi qualcosa di sbagliato o migliorabile?
« Ultima modifica: 28 Settembre 2014, 12:59:37 CEST da sismouse »

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 timeout connessione
« Risposta #4 il: 28 Settembre 2014, 12:06:30 CEST »
+1
Sebbene la tua idea sia molto valida, siccome sono davvero alle prime armi con lo sviluppo per Android, vorrei scrivere del codice nativo... e capire dove sbaglio o posso scriverlo meglio.
Riguardo il codice che ho postato, parzialmente scopiazzato da internet, sai dirmi se c'è qualcosa che non va?

E' proprio leggendo rapidamente il codice che mi è saltata all'occhio la cosa che ti ho detto: nessuno scrive più richieste di rete "a mano", nessuno tranne quelli che realizzano le librerie in questione. E' proprio il caso di dire che la "best practice" è proprio fare ricorso a queste librerie e NON scriversi a mano quelle parti di codice.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline sismouse

  • Utente junior
  • **
  • Post: 69
  • Respect: 0
    • Mostra profilo
Re:AsyncTask e timeout connessione
« Risposta #5 il: 28 Settembre 2014, 19:10:16 CEST »
0
E come dovrei fare per implementare tale libreria?

Offline emaborsa

  • Utente normale
  • ***
  • Post: 274
  • Java Developer
  • Respect: +33
    • Google+
    • emaborsa
    • Mostra profilo
    • www.emaborsa.com
  • Dispositivo Android:
    Samsung Galaxy S2
  • Sistema operativo:
    Linux 10 - Win8.1 - Android 4.1.2
Re:AsyncTask e timeout connessione
« Risposta #6 il: 03 Ottobre 2014, 17:22:34 CEST »
+1
Eccomi, non conoscendo tutto il tuo codice non posso sapere come hai fatto il tutto. Inoltre non ho ancora capito qual'è il PROBLEMA. Mi hai scritto come si comporta, ma non ho capito come dovrebbe essere.

Comunque, il pure ho scritto una classe che fa richieste via AsynkTask, ma ho aggiunto anche un timer per segnalare il timeout:

Codice (Java): [Seleziona]
public class MyClass {
   
    private Timer timer;
    private Task task;

    public void startTask(){
        timer = new Timer();
        timer.start();

        task = new Task();
        task.execute();

    private class Task extends AsynkTask<Void, Void, String>{

        public String doInBackground(Void...params){
              //fai ciò che devi fare
              return "";
        }

        public void onPostExecute(String result){
              if (timer != null && timer.isRunning()){
                  //fai ciò che devi fare
             }
        }

    }

    private class Timer extends CountDownTimer {
        private long millis = 3000; // 3 secondi

        public Timer(){
            super(millis, millis);
        }

        public void onTick(){
            //se vuoi implementi qualcosa
        }

        public void onFinish(){
            if (task != null && task.isRunning()){
                //se vuoi implementi qualcosa
            }
        }
    }

}

Il codice l'ho scritto a mano senza IDE, perciò potrebbero esserci degli errori di compilazione.
Al momento non posso verificare, dato che il mio PC principale è fuori uso.

Come librerie, io uso Apache-Commons...

Se hai ancora dubbi o problemi, spiegameli.

Offline sismouse

  • Utente junior
  • **
  • Post: 69
  • Respect: 0
    • Mostra profilo
Re:AsyncTask e timeout connessione
« Risposta #7 il: 03 Ottobre 2014, 18:34:35 CEST »
0
Dunque ricapitolo:

All'avvio della mia app compare un alterbox che indica lo stato di avanzamento di un processo (download, parsing e scrittura su db locale). Questo processo però senza una connessione ad internet non può avvenire e vorrei dunque gestire la mancanza o la scarsità di rete.
Quindi ho scritto del codice per gestire questo (o almeno credo di averlo fatto): se non c'è proprio la connessione (mancanza di campo o modalità aeroplano) riesco a far uscire un alertbox (A) che dice che la connessione non può avvenire (e si chiude l'app); se invece la connessione è scarsa, dopo 3 secondi di impossibilità a connettersi (va dunque in timeout), mi deve avvisare con un ulteriore alertbox (B) che la linea è lenta e deve chiedere se si vuole riprovare o uscire dall'app.
Ebbene raramente sono riuscito a far visualizzare B.

Se la rete non c'è proprio compare senza problemi A;
se invece la linea è scarsa, succede una delle tre cose:
- l'alertbox relativo allo stato di avanzamento resta a 0% e nonostante trascorrino più di 3 secondi B non compare... ma dopo un po' il download riesce a completarsi avanzando fino al 100% e l'operazione si conclude con successo;
- dopo tot secondi in cui non riesce a connettersi (e in cui l'avanzamento resta a 0%), esce dall'alertbox (B non compare) e fallisce direttamente tutta l'operazione
- compare l'alertbox tanto desiderato (B) che indica che la connessione è scarsa e che chiede quindi se chiudere o riprovare

Quest'ultimo punto ACCADE MOLTO RARAMENTE, mentre invece dovrebbe accadere tutte le volte che la connessione è scarsa!


Riguardo il tuo codice non ho capito come utilizzi la libreria che hai citato (che non conosco :()

Spero di essere riuscito a spiegarmi :'(

Offline emaborsa

  • Utente normale
  • ***
  • Post: 274
  • Java Developer
  • Respect: +33
    • Google+
    • emaborsa
    • Mostra profilo
    • www.emaborsa.com
  • Dispositivo Android:
    Samsung Galaxy S2
  • Sistema operativo:
    Linux 10 - Win8.1 - Android 4.1.2
Re:AsyncTask e timeout connessione
« Risposta #8 il: 03 Ottobre 2014, 18:50:26 CEST »
0
Chiaro. Ti consiglio di farti un Timer che gestisca il timeout a parte...usando il CountDownTimer

Offline Illogica

  • Nuovo arrivato
  • *
  • Post: 32
  • Respect: +4
    • Google+
    • Mostra profilo
    • Illogica Software
  • Dispositivo Android:
    Caterpillar B15Q / Asus Padfone Infinity / Htc Pyramid / Samsung Galaxy *
  • Play Store ID:
    Illogica Software
  • Sistema operativo:
    Ubuntu 14.04
Re:AsyncTask e timeout connessione
« Risposta #9 il: 05 Ottobre 2014, 08:13:54 CEST »
+1
Un Thread per gestire il timeout è sicuramente una buona pratica. Secondo me  usare un Handler è ancora più elegante e conciso, basta che lo dichiari quando lanci il tuo AsyncTask:

Codice: [Seleziona]
public static final long DEFAULT_ASYNCTASK_TIMEOUT = 3000;  // 3 secondi
final DownloadDataFromServer downloadDataFromServerTask = new DownloadDataFromServer();
            downloadDataFromServerTask.execute();
            Handler downloadDataFromServerTaskTimeoutHandler = new Handler();
            downloadDataFromServerTaskTimeoutHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (downloadDataFromServerTask.getStatus() == AsyncTask.Status.RUNNING) {
                        //codice da eseguire quando l'Asynctask va in timeout, per esempio:
                        //downloadDataFromServerTask.cancel(true);
                    }
                }
            }, DEFAULT_ASYNCTASK_TIMEOUT);


Poi avrei un paio di consigli:
- vedo che usi un ProgressDialog per notificare l'utente che c'è un'operazione in corso, come mostrato negli esempi di Google. Questo nella vita reale ha due controindicazioni: se per esempio l'utente tocca lo schermo fuori della ProgressDialog questa sparisce senza lasciare traccia (ok, può essere trascurabile) e se ruoti lo schermo mentre le operazioni sono in corso la tua app si chiuderà in modo anomalo a meno che non salvi lo stato della ProgressDialog in onSavedInstanceState e la ripristini successivamente; questo perchè il tuo AsyncTask sopravvive alla rotazione dello schermo, e chiamerà una ProgressDialog che nel frattempo è stata distrutta.
- le operazioni che usi dentro AsyncTask non dovrebbero contaminare il mondo esterno se non tramite "onPostExecuted". Tu esegui transazioni sul database basate su letture di stringhe Json dentro "doInBackground": è meglio salvare le stringhe Json in una variabile interna all'AsyncTask e solo quando le operazioni di rete sono finite eseguire le transazioni in "onPostExecuted".

Offline sismouse

  • Utente junior
  • **
  • Post: 69
  • Respect: 0
    • Mostra profilo
Re:AsyncTask e timeout connessione
« Risposta #10 il: 09 Ottobre 2014, 17:39:30 CEST »
0
Un Thread per gestire il timeout è sicuramente una buona pratica. Secondo me  usare un Handler è ancora più elegante e conciso, basta che lo dichiari quando lanci il tuo AsyncTask:

Codice: [Seleziona]
public static final long DEFAULT_ASYNCTASK_TIMEOUT = 3000;  // 3 secondi
final DownloadDataFromServer downloadDataFromServerTask = new DownloadDataFromServer();
            downloadDataFromServerTask.execute();
            Handler downloadDataFromServerTaskTimeoutHandler = new Handler();
            downloadDataFromServerTaskTimeoutHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (downloadDataFromServerTask.getStatus() == AsyncTask.Status.RUNNING) {
                        //codice da eseguire quando l'Asynctask va in timeout, per esempio:
                        //downloadDataFromServerTask.cancel(true);
                    }
                }
            }, DEFAULT_ASYNCTASK_TIMEOUT);
Ho provato ad usare il tuo codice, ma non ho capito cosa scrivere al posto di AsyncTask (riga 8 del tuo codice) e inoltre non ho capito se questa chicca che mi hai suggerito è compatibile con la parte di codice scritta da me riguardante la connessione ad internet. Oppure va cambiato qualcosa anche lì? Mi riferisco al metodo connectAndCreateJsonArray();

Citazione
Poi avrei un paio di consigli:
- vedo che usi un ProgressDialog per notificare l'utente che c'è un'operazione in corso, come mostrato negli esempi di Google. Questo nella vita reale ha due controindicazioni: se per esempio l'utente tocca lo schermo fuori della ProgressDialog questa sparisce senza lasciare traccia (ok, può essere trascurabile) e se ruoti lo schermo mentre le operazioni sono in corso la tua app si chiuderà in modo anomalo a meno che non salvi lo stato della ProgressDialog in onSavedInstanceState e la ripristini successivamente; questo perchè il tuo AsyncTask sopravvive alla rotazione dello schermo, e chiamerà una ProgressDialog che nel frattempo è stata distrutta.
Cavoli, questo si è che un bug! Però sono alle prime armi quindi sono perdonabile :)
Per quanto riguardo il tocco esterno alla progressbar avevo già risolto settando dialog.setCancelable(false); per quanto riguarda invece la rotazione non saprei proprio come gestire il salvataggio dell'instance e il successivo ripristino stesso nella progressbar. Puoi anche in questo caso mostrami il codice o un esempio? Ho provato a leggere il lifecycle delle app, ma non so come comportarmi nel caso di una progressbar di un AsyncTask.

Citazione
- le operazioni che usi dentro AsyncTask non dovrebbero contaminare il mondo esterno se non tramite "onPostExecuted". Tu esegui transazioni sul database basate su letture di stringhe Json dentro "doInBackground": è meglio salvare le stringhe Json in una variabile interna all'AsyncTask e solo quando le operazioni di rete sono finite eseguire le transazioni in "onPostExecuted".
Per stringa Json intendi quello restituito dal metodo getParsedMerchantEntry()? Anche in questo caso, potresti aiutarmi con il codice?
Te ne sarei molto grato!

Offline Illogica

  • Nuovo arrivato
  • *
  • Post: 32
  • Respect: +4
    • Google+
    • Mostra profilo
    • Illogica Software
  • Dispositivo Android:
    Caterpillar B15Q / Asus Padfone Infinity / Htc Pyramid / Samsung Galaxy *
  • Play Store ID:
    Illogica Software
  • Sistema operativo:
    Ubuntu 14.04
Re:AsyncTask e timeout connessione
« Risposta #11 il: 09 Ottobre 2014, 19:45:51 CEST »
+1
Ho provato ad usare il tuo codice, ma non ho capito cosa scrivere al posto di AsyncTask (riga 8 del tuo codice) e inoltre non ho capito se questa chicca che mi hai suggerito è compatibile con la parte di codice scritta da me riguardante la connessione ad internet. Oppure va cambiato qualcosa anche lì? Mi riferisco al metodo connectAndCreateJsonArray();
Il codice che hai postato è relativo l'asynctask che usi, e va bene. Da qualche altra parte nelle tue activity o nei tuoi fragment lancerai l'asynctask tramite il suo metodo execute() (riga 3 del codice che ti ho postato). A questo punto ci attacchi un Handler che dopo n millisecondi scade (riga 4). Quando scade, l'handler esegue il suo metodo run() (riga 7) e interroga l'asynctask che hai lanciato chiedendogli: "il tuo status è RUNNING?" (riga 8) e a questo punto se la risposta è "true", vuol dire che l'asynctask non è ancora terminato.
Quindi l'Handler lo aggiungi solo dove dichiari la tua istanza dell'asynctask.

Citazione
Cavoli, questo si è che un bug! Però sono alle prime armi quindi sono perdonabile :)
Stiamo tutti imparando ;)

Citazione
Per quanto riguardo il tocco esterno alla progressbar avevo già risolto settando dialog.setCancelable(false);
Chapeau

Citazione
per quanto riguarda invece la rotazione non saprei proprio come gestire il salvataggio dell'instance e il successivo ripristino stesso nella progressbar. Puoi anche in questo caso mostrami il codice o un esempio? Ho provato a leggere il lifecycle delle app, ma non so come comportarmi nel caso di una progressbar di un AsyncTask.
Non vorrei sembrare lapidario... ma abbandona le Dialog. Guarda per esempio l'app di Facebook: scarica continuamente dati dal server, ma ti mostra una ProgressDialog integrata nel layout, non sovrapposta al layout.
E' una cosa banale ed estremamente efficace: nel layout della tua activity includi un piccolo layout (relative o linear, come ti viene meglio) magari sulla parte alta o bassa dello schermo con dentro una progressBar (e volendo fare i fighi anche una TextView da aggiornare tramite il metodo onProgressupdate() del tuo asynctask, ma andiamo per gradi...). Dai un id a piacere al layout che contiene la progressBar, per esempio "layout_network_operation" ed imposta la visibilità del layout come GONE (invisibile, come se non ci fosse mai stato).
A questo punto basta che imposti la visibilità di layout_network_operation a VISIBLE prima di lanciare l'asynctask e la reimposti a GONE quando l'asynctask termina.
Et voilà: una progressbar che salta fuori solo quando scarichi dati dalla Rete e anche se ruoti lo schermo non fa arrabbiare Android.
Momento auto promozionale: un esempio di questo approccio lo puoi vedere nella mia app di barzellette, quando scarica barzellette dal server compare una simpatica scimmietta che ti racconta cosa sta succedendo, e non è altro che un RelativeLayout dentro al layout principale della activity.

Citazione
Per stringa Json intendi quello restituito dal metodo getParsedMerchantEntry()? Anche in questo caso, potresti aiutarmi con il codice?
Te ne sarei molto grato!
Proviamo a riordinare il codice in modo che doInBackGround() si limiti a scaricare i dati. Tutte le elaborazioni e transazioni sul db le facciamo in onPostExecute():

Codice (Java): [Seleziona]
private class DownloadDataFromServer extends AsyncTask<String, Integer, String> {
        ProgressDialog dialog;
        boolean connErr = false;
        boolean soErr = false;
        JSONArray UserJsonArray = new JSONArray();

        @Override
        protected void onPreExecute() {
            dialog = new ProgressDialog(HomePage.this);
            dialog.setIndeterminate(false);
            dialog.setMax(100);
            dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            dialog.setCancelable(false);
            dialog.setTitle("Download");
            dialog.setMessage("Aggiornamento dati in corso. Prego attendere...");
            dialog.show();

            super.onPreExecute();
        }

        @Override
        protected String doInBackground(String... urls) {
            UserJsonArray = connectAndCreateJsonArray(urls[0]);

            return UserJsonArray.length() + "";
        }

        private JSONArray connectAndCreateJsonArray(String url) {
            JSONArray jsonArray = new JSONArray();

            try {
                HttpGet request = new HttpGet(url);
                HttpParams httpParameters = new BasicHttpParams();

                // timeout until connection is established
                int timeOutInMillis = 3000;
                HttpConnectionParams.setConnectionTimeout(httpParameters, timeOutInMillis);

                // timeout until data is received
                int socketTimeOutinMillis = 3000;
                HttpConnectionParams.setSoTimeout(httpParameters, socketTimeOutinMillis);

                // create a client with the parameters
                DefaultHttpClient client = new DefaultHttpClient(httpParameters);
                HttpResponse response = client.execute(request);

                request.addHeader("Cache-Control", "no-cache");

                HttpEntity entity = response.getEntity();
                InputStreamReader in = new InputStreamReader(entity.getContent());
                BufferedReader reader = new BufferedReader(in);
                StringBuilder stringBuilder = new StringBuilder();
                String line = "";
                while ((line = reader.readLine()) != null) {
                    stringBuilder.append(line);
                }

                jsonArray = new JSONArray(stringBuilder.toString());

            } catch (SocketTimeoutException e) {
                connErr = true;
                e.printStackTrace();
            } catch (SocketException e) {
                soErr = true;
                e.printStackTrace();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
            }

            return jsonArray;
        }

        private ContentValues getParsedUserEntry(JSONObject entry) {
            ContentValues values = new ContentValues();

            values.put("_id", entry.optString("id").toString());
            values.put("nome", entry.optString("name").toString());
            values.put("cognome", entry.optString("surname").toString());

            return values;
        }

        protected void onProgressUpdate(Integer... progress) {
            dialog.setProgress(progress[0]);
        }

        @Override
        protected void onPostExecute(String result) {
            int count = 0;
            int numUtenti = 0;
            SQLiteDatabase localDB = db.getWritableDatabase();
            try {
                numUtenti = UserJsonArray.length();
                localDB.beginTransaction();

                for (int i = 0; i < numUtenti; i++) {
                    JSONObject jObj = (JSONObject) UserJsonArray.getJSONObject(i);

                    localDB.insert("users", null, getParsedUserEntry(jObj));

                    count++;
                    publishProgress(count * 100 / numUtenti);
                }

                localDB.setTransactionSuccessful();

            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
                Log.e("Msg", "catch");
            } finally {
                localDB.endTransaction();
            }
           
            Log.e("Connessione", connErr+"");
            Log.e("Socket", soErr+"");
            if (connErr || soErr) {
                String msg = "Connessione lenta o non funzionante";
                AlertDialog.Builder builder;
                builder = new AlertDialog.Builder(HomePage.this);
                builder.setCancelable(false);
                builder.setTitle("Timeout connessione");
                builder.setMessage(msg);

                builder.setPositiveButton("Riprova", new DialogInterface.OnClickListener(){
                    @Override
                    public void onClick(DialogInterface dialog, int which)
                    {
                        dialog.dismiss();
                        new DownloadDataFromServer().execute(new String[] { "http://www.miosito.org/getUsers.php" });
                    }
                });

                builder.setNegativeButton("Esci", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        finish();
                    }
                });
                AlertDialog dialog = builder.create();
                dialog.show();
            } else {
                if (Integer.parseInt(result) <= 0) {
                    Toast.makeText(getBaseContext(), "Scrittura database fallita!", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(getBaseContext(), "Aggiornamento riuscito", Toast.LENGTH_SHORT).show();
                }
            }
            dialog.dismiss();
        }
    }

Offline sismouse

  • Utente junior
  • **
  • Post: 69
  • Respect: 0
    • Mostra profilo
Re:AsyncTask e timeout connessione
« Risposta #12 il: 10 Ottobre 2014, 02:06:05 CEST »
0
Ho letto tutto il tuo post ma mi ci applico domani che a quest'ora non riesco a fare granché... però al volo ho riprovato l'handler... e funziona!!!
In pratica nel mio post precedente ti avevo chiesto cosa scrivere al posto di "AsyncTask" perché mi veniva segnato come errore... alla fine era Eclipse che non mi suggeriva di effettuare (giustamente) l'import della classe AsyncTask.
L'ho inserito a mano e l'ho testato al volo... domani vedo meglio e ti aggiorno. Intanto ti ringrazio molto per la tua pazienza!

Post unito: [time]10 Ottobre 2014, 10:06:38 CEST[/time]
Ciao, dunque, risolviamo prima il timeout poi vediamo il resto. Sto riscontrando dei problemi e dopo alcune verifiche ho visto che downloadDataFromServerTask.cancel(true); non funziona, ovvero dopo 3 secondi la progressbar è ancora lì.
La terminazione dell'AsyncTask non dovrebbe lanciare onPostExecute che a sua volta lancia dialog.dismiss?

EDIT: ho risolto... ho sovrascritto il metodo onCancelled:

Codice: [Seleziona]
        protected void onCancelled() {
                dialog.dismiss();
                super.onCancelled();
        }

Ora però, sempre con quest'AsyncTask, io faccio comparire un AlertDialog dopo i 3 secondi in cui l'utente sceglie se riprovare o uscire dall'app. Ebbene quando preme su Riprova, ovviamente lancio una nuova istanza di AsyncTask... però questa volta non c'è controllo sul timeout. Come risolvo? Aggiungo un nuovo handler anche qui?

Codice: [Seleziona]
    public void timeoutAlertDialog() {
                String msg = "Connessione lenta o non funzionante";
                AlertDialog.Builder builder;
            builder = new AlertDialog.Builder(Main.this);
            builder.setCancelable(false);
            builder.setTitle("Timeout connessione");
            builder.setMessage(msg);
               
            builder.setPositiveButton("Riprova", new DialogInterface.OnClickListener(){
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                dialog.dismiss();
                //new DownloadDataFromServer(Main.this).execute(new String[] { "http://www.example.com" });
            }
        });
       
            builder.setNegativeButton("Esci", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                finish();
            }
        });                   
        AlertDialog dialog = builder.create();
        dialog.show();
    }


EDIT2: ho risolto con 2 metodi che si chiamano a vicenda! Ma è lecista sta cosa?

Codice: [Seleziona]
    public void downloadDialog() {
                final DownloadDataFromServer downloadTask = new DownloadDataFromServer(this);
        downloadTask.execute(new String[] { "http://www.example.com" });
        Handler downloadTaskTimeout = new Handler();
        downloadTaskTimeout.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (downloadTask.getStatus() == AsyncTask.Status.RUNNING) {
                    downloadTask.cancel(true);
                        timeoutAlertDialog();
                }
            }
        }, DEFAULT_ASYNCTASK_TIMEOUT);
    }
   
    public void timeoutAlertDialog() {
                String msg = "Connessione lenta o non funzionante";
                AlertDialog.Builder builder;
            builder = new AlertDialog.Builder(Main.this);
            builder.setCancelable(false);
            builder.setTitle("Timeout connessione");
            builder.setMessage(msg);
               
            builder.setPositiveButton("Riprova", new DialogInterface.OnClickListener(){
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                dialog.dismiss();
                downloadDialog();
            }
        });
       
            builder.setNegativeButton("Esci", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                finish();
            }
        });                   
        AlertDialog dialog = builder.create();
        dialog.show();
    }
« Ultima modifica: 10 Ottobre 2014, 10:25:54 CEST da sismouse »

Offline sismouse

  • Utente junior
  • **
  • Post: 69
  • Respect: 0
    • Mostra profilo
Re:AsyncTask e timeout connessione
« Risposta #13 il: 11 Ottobre 2014, 11:10:39 CEST »
0
Ciao illogica, se mi confermi che ho fatto bene i compiti per quanto riguarda il post precedente, procedo con il discutere il resto...

Offline Illogica

  • Nuovo arrivato
  • *
  • Post: 32
  • Respect: +4
    • Google+
    • Mostra profilo
    • Illogica Software
  • Dispositivo Android:
    Caterpillar B15Q / Asus Padfone Infinity / Htc Pyramid / Samsung Galaxy *
  • Play Store ID:
    Illogica Software
  • Sistema operativo:
    Ubuntu 14.04
Re:AsyncTask e timeout connessione
« Risposta #14 il: 11 Ottobre 2014, 11:19:21 CEST »
0
Si, anche secondo me è la soluzione migliore: giustamente hai scritto un metodo crea e che lancia l'asynctask con attaccato un handler, quindi ogni volta che ti serve l'asynctask chiami il tuo metodo da qualsiasi parte del tuo codice.