Autore Topic: Consiglio per richiesta asincrona tramite http  (Letto 505 volte)

Offline array81

  • Utente junior
  • **
  • Post: 64
  • Respect: 0
    • Mostra profilo
    • MartinZone
  • Dispositivo Android:
    OnePlus One, Nexus S
  • Play Store ID:
    MartinZone
  • Sistema operativo:
    Windows 7
Consiglio per richiesta asincrona tramite http
« il: 22 Settembre 2014, 19:22:01 CEST »
0
Nella mia applicazione ho la necessità di fare alcune richieste asincrone (non voglio bloccare la GUI) tramite protocollo HTTP.
Alcune di queste richieste sono veloci in quanto richiedono dati in formato JSON al mio server, altre invece necessitano di più tempo dato che devono scaricare dei files.
Durante una richiesta asincrona mostro sempre un dialog, o del tipo con il "cerchietto" se la richiesta si suppone veloce, o con barra di progresso se la richiesta é lenta (es. download file).
Questo é un esempio del codice che uso:

Codice (Java): [Seleziona]
public class MyFileDownloadTask extends AsyncTask<String, Integer, String> {

    private MyFileActivity activity;
    private ProgressDialogFragment pDialog;
    private String nProvincia;
    private String nFile;
    private String nURL;

    public MyFileDownloadTask(String code_province, String name_file, String url_file) {
        nProvincia = code_province;
        nFile = name_file;
        nURL = url_file;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        pDialog = ProgressDialogFragment.newInstance("Caricamento MyFile", "Download file MyFile. Attendere...", 100);

        try {
            pDialog.show(activity.getFragmentManager(), "MyFile_task_download");
        } catch (IllegalStateException activityClosed) {
        } /* Catch blocks happens when the library tries to open a dialog,
              but the activity is already closed, so generates a NullPointerException or IllegalStateException.
                         In this way, a force close is avoided.*/

    }

    @Override
    protected String doInBackground(String... Url) {
        try {
            File file = new File(nFile);

            try {
                file.createNewFile();
            } catch (IOException e) {
                //activity.showToast("Impossibile creare file MyFile su memoria!");
            }

            URL url = new URL(nURL);
            URLConnection connection = url.openConnection();
            connection.setConnectTimeout(8000);
            connection.setReadTimeout(8000);
            connection.connect();

            int fileLength = connection.getContentLength();

            InputStream input = new BufferedInputStream(url.openStream(), 8192);
            OutputStream output = new FileOutputStream(file);

            byte data[] = new byte[1024];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                total += count;
                // Publish the progress
                publishProgress((int) (total * 100 / fileLength));
                // writing data to file
                output.write(data, 0, count);
            }

            output.flush();
            output.close();
            input.close();

            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    pDialog.setMessage(activity.getFragmentManager(), "Caricamento dati nel database. Attendere...");
                }
            });

            try {
                                // LEGGO I DATI DAL FILE E LI COPIO NEL DATABASE
            }
            catch (final IOException ioe) {
                Log.e("MyApp", "Errore importazione MyFile nel DB:" + ioe.getMessage());
            }

        } catch (SocketTimeoutException e) {
            Log.e("MyApp", "Timeout durante il download del file MyFile");
        } catch (Exception e) {
            Log.e("MyApp", "Errore sconosciuto durante il caricamento del file MyFile: " + e.getMessage());
        }

        return null;
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        pDialog.setProgress(activity.getFragmentManager(), progress[0]);
    }

    @Override
    protected void onPostExecute(String result) {
        if (activity != null) {
            // use the new activity reference just incase it was re-attached
//            activity.getFragmentManager().beginTransaction().remove(pDialog).commitAllowingStateLoss();

            try {
                pDialog.dismiss(activity.getFragmentManager());
            } catch (Exception e) {
                Log.e("MyApp", "Errore dismissione progress dialog MyFile: " + e.getMessage());
                activity.fillListView(false);
                activity.showToast("Caricamento MyFile terminato.");
            }


            // reference UI updates using activity
            //activity.updateUI();
            activity.fillListView(false);
            activity.showToast("Caricamento MyFile terminato.");
        }

        // remove the reference
        MyFileDownloadTaskHelper.getInstance().removeTask("MyFile_task_download");
    }

    /**
     * Attaches an activity to the task
     * @param a The activity to attach
     */

    public void attach(Activity a) {
        this.activity = (MyFileActivity)a;
    }

    /**
     * Removes the activity from the task
     */

    public void detach() {
        this.activity = null;
    }
}

Visto che sono alle prime armi vorrei sapere se il mio approccio é corretto. Ho letto su qualche articolo su internet che l'uso di AsyncTask per fare questo tipo di cose non é consigliato per diversi motivi, ad esempio ci potrebbero essere problemi durante la rotazione del dispositivo (io non li ho riscontrati) e viene quindi consigliato di usare librerie specifiche.
Personalmente non ho riscontrato problemi, tuttavia un numero molto (molto) limitato di miei utenti riportano errori riconducibili a questa classe.

Vorrei avere un parere da un esperto. Come vedete io uso la calsse di cui sopra sia per il download che per il trattamento dei dati scaricati.

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:Consiglio per richiesta asincrona tramite http
« Risposta #1 il: 22 Settembre 2014, 19:35:55 CEST »
0
Senza stare a disquisire troppo, varrebbe la pena usare una libreria esterna (tipo okhttp) anche solo perchè tutto quel codice lo ridurresti ad una manciata di righe. Oltre a ricevere gratis il supporto a tutta una serie di casistiche non banali sulle richieste di rete.

E gestire "a mano" una UrlConnection ormai è diventato obsoleto con queste librerie, che io sappia non lo fa più nessuno.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline array81

  • Utente junior
  • **
  • Post: 64
  • Respect: 0
    • Mostra profilo
    • MartinZone
  • Dispositivo Android:
    OnePlus One, Nexus S
  • Play Store ID:
    MartinZone
  • Sistema operativo:
    Windows 7
Re:Consiglio per richiesta asincrona tramite http
« Risposta #2 il: 22 Settembre 2014, 22:17:33 CEST »
0
Senza stare a disquisire troppo, varrebbe la pena usare una libreria esterna (tipo okhttp) anche solo perchè tutto quel codice lo ridurresti ad una manciata di righe. Oltre a ricevere gratis il supporto a tutta una serie di casistiche non banali sulle richieste di rete.

E gestire "a mano" una UrlConnection ormai è diventato obsoleto con queste librerie, che io sappia non lo fa più nessuno.

Ho capito, mi sto documentando a tal riguardo su Retrofit che, almeno leggendo in giro, sembra essere tra le migliori. Questo per quanto riguarda il "lato rete", ma per caricare i dati che scarico nel db (operazione che può richiedere anche qualche minuto), un approccio tramite AsyncTask é corretto oppure anche per questo mi consigli qualche libreria?


ALTRA COSA: vedo che sei un moderatore, ho provato più volte a contattare l'amministratore del sito in quanto non riesco a postare nella sezione "il vostro software", dato che il tasto per aprire discussione non mi compare in quella sezione. Vorrei sapere come fare. Grazie.

iClaude

  • Visitatore
Re:Consiglio per richiesta asincrona tramite http
« Risposta #3 il: 25 Settembre 2014, 10:36:59 CEST »
0
Ho capito, mi sto documentando a tal riguardo su Retrofit che, almeno leggendo in giro, sembra essere tra le migliori. Questo per quanto riguarda il "lato rete", ma per caricare i dati che scarico nel db (operazione che può richiedere anche qualche minuto), un approccio tramite AsyncTask é corretto oppure anche per questo mi consigli qualche libreria?


ALTRA COSA: vedo che sei un moderatore, ho provato più volte a contattare l'amministratore del sito in quanto non riesco a postare nella sezione "il vostro software", dato che il tasto per aprire discussione non mi compare in quella sezione. Vorrei sapere come fare. Grazie.

Il problema non è l'AsyncTask in quanto tale, ma il fatto di collocarlo in una Activity, che ha un ciclo di vita spesso scollegato da quello delle operazioni in background.
Per risolvere il problema basta usare un Service all'interno del quale mettere l'AsyncTask.