Autore Topic: Thread e ProgressBar  (Letto 1345 volte)

Offline MrKrabs

  • Utente junior
  • **
  • Post: 94
  • Respect: +4
    • Mostra profilo
Thread e ProgressBar
« il: 14 Gennaio 2012, 00:20:53 CET »
0
Ciao a tutti,
ho un problema col seguente codice che non va (si esce dall'applicazione)

aggiorna() è una funzione che fa il parseHtml quindi impiega abbastanza tempo ed in più riempie con del testo delle TextView.

Codice (Java): [Seleziona]
//THREAD 1
                    new Thread(new Runnable(){
                    public void run(){          
                                aggiorna();
                    }
                        }).start();
//THREAD 2                     
                    new Thread(new Runnable(){
                    public void run(){
                       
                        while (progressStatus < 100){
                                try {
                                                                Thread.sleep(500);
                                                        } catch (InterruptedException e) {
                                                                // TODO Auto-generated catch block
                                                                e.printStackTrace();
                                                        }
                                                        progress = progress+5;
                            progressStatus = progress;
                            //---Update the progress bar---
                            handler.post(new Runnable()
                            {   public void run() {
                                    progress_bar.setProgress(progressStatus);
                                }
                            });
                        }
                        //---hides the progress bar---
                        handler.post(new Runnable()
                        {   public void run() {
                                //---0 - VISIBLE; 4 - INVISIBLE; 8 - GONE---
                                progress_bar.setVisibility(8);
                            }
                        });
                    }  
                }).start();

Eliminando il primo thread tutto funziona, ma naturalmente la funzione aggiorna() fa attendere la sua esecuzione senza che la progressbar si avvi.
Questo è il codice "funzionante":
Codice (Java): [Seleziona]
new Thread(new Runnable(){
           
                    aggiorna();
                               
                    new Thread(new Runnable(){
                    public void run(){
                       
                        while (progressStatus < 100){
                                try {
                                                                Thread.sleep(500);
                                                        } catch (InterruptedException e) {
                                                                // TODO Auto-generated catch block
                                                                e.printStackTrace();
                                                        }
                                                        progress = progress+5;
                            progressStatus = progress;
                            //---Update the progress bar---
                            handler.post(new Runnable()
                            {   public void run() {
                                    progress_bar.setProgress(progressStatus);
                                }
                            });
                        }
                        //---hides the progress bar---
                        handler.post(new Runnable()
                        {   public void run() {
                                //---0 - VISIBLE; 4 - INVISIBLE; 8 - GONE---
                                progress_bar.setVisibility(8);
                            }
                        });
                    }  
                }).start();

Codice: [Seleziona]
01-13 23:15:55.736: E/AndroidRuntime(1938): FATAL EXCEPTION: Thread-153
01-13 23:15:55.736: E/AndroidRuntime(1938): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4039)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:709)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.view.View.requestLayout(View.java:12675)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.view.View.requestLayout(View.java:12675)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.view.View.requestLayout(View.java:12675)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.view.View.requestLayout(View.java:12675)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.view.View.requestLayout(View.java:12675)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.view.View.requestLayout(View.java:12675)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.widget.AbsListView.requestLayout(AbsListView.java:1690)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.view.View.requestLayout(View.java:12675)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.view.View.requestLayout(View.java:12675)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.view.View.requestLayout(View.java:12675)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.view.View.requestLayout(View.java:12675)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.widget.TextView.checkForRelayout(TextView.java:6773)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.widget.TextView.setText(TextView.java:3306)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.widget.TextView.setText(TextView.java:3162)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at android.widget.TextView.setText(TextView.java:3137)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at it.***********.gethtml.Finestra.aggiorna(Finestra.java:169)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at it.***********.gethtml.Finestra$2$1.run(Finestra.java:124)
01-13 23:15:55.736: E/AndroidRuntime(1938):         at java.lang.Thread.run(Thread.java:856)


Only the original thread that created a view hierarchy can touch its views.
Cosa vorrà dire? Qualche idea?
« Ultima modifica: 14 Gennaio 2012, 01:16:59 CET da MrKrabs »

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:Thread e ProgressBar
« Risposta #1 il: 14 Gennaio 2012, 09:36:48 CET »
0
Con una premessa appare tutto più ovvio: il concetto di base delle applicazioni Android è che il thread principale (e solo quello) gestisce la UI, mentre tutti gli altri fanno il lavoro pesante; quando un thread "lavorante" vuole cambiare la UI, lo "chiede" al thread principale.

Se lavori direttamente con i Thread, devi spedire un messaggio al thread principale, che lo riceverà usando un Handler, ed eseguirà l'aggiornamento. C'è un esempio minimale di Thread con messaggi nella sezione tutorial.
[medio] Introduzione ai Thread - Android Developers Italia

Molto molto più semplice è usare gli AsyncTask, che sono di fatto Thread con le funzioni per comunicare con il thread principale già pronte per l'uso. Anche di questo c'è un tutorial.
[facile] HttpBookSearch: AsyncTask, HttpClient, XML parsing, ProgressDialog - Android Developers Italia

NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline MrKrabs

  • Utente junior
  • **
  • Post: 94
  • Respect: +4
    • Mostra profilo
Re:Thread e ProgressBar
« Risposta #2 il: 14 Gennaio 2012, 14:42:24 CET »
0
Ciao bradipao,
grazie per la tua risposta, mi sei stato di grande aiuto.
Ora capendo il concetto che
Citazione
il thread principale (e solo quello) gestisce la UI
mi è chiaro l'errore.
Alla fine ho utilizzato un AsyncTask come tu mi hai consigliato e tutto funziona per bene.

L'unico problema è che adesso ho una progressDialog e non una progressBar come volevo.
Può sembrare stupido quello che dico, ma pensandoci, come è possibile fare una progressBar che si completi man mano fino a riempirsi proprio quando le operazioni di aggionamento sono finite?

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:Thread e ProgressBar
« Risposta #3 il: 15 Gennaio 2012, 12:52:42 CET »
+1
Ciao bradipao,
grazie per la tua risposta, mi sei stato di grande aiuto.
Ora capendo il concetto che  mi è chiaro l'errore.
Alla fine ho utilizzato un AsyncTask come tu mi hai consigliato e tutto funziona per bene.

L'unico problema è che adesso ho una progressDialog e non una progressBar come volevo.
Può sembrare stupido quello che dico, ma pensandoci, come è possibile fare una progressBar che si completi man mano fino a riempirsi proprio quando le operazioni di aggionamento sono finite?


Nella onPreExecute() dell'AsyncTask definisi lo stile a barra orizzontale della ProgressDialog :

Codice (Java): [Seleziona]
      @Override
      protected void onPreExecute() {
         progressDialog = new ProgressDialog(mContext);
         progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
         progressDialog.setMessage("Scanning Packages...");
         progressDialog.setCancelable(false);
         progressDialog.setProgress(0);
         progressDialog.setMax(0);
         progressDialog.show();
      }

Nella doInBackground() avrai qualcosa tipo un ciclo e ad ogni giro richiami la publishprogress:

Codice (Java): [Seleziona]
@Override
   protected Integer[] doInBackground(Void... voids) {
      ...
      publishProgress(i,max);
      ...
   }

La onProgressUpdate() riceve il messaggio publishProgress e lo esegue DENTRO al thread di UI aggiornando la posizione della bar:

Codice (Java): [Seleziona]
      @Override
      protected void onProgressUpdate(Integer... progress) {
         progressDialog.setProgress(progress[0]);
         progressDialog.setMax(progress[1]);
      }


Alla fine nella onPostExecute() chiudi la dialog:

Codice (Java): [Seleziona]
      @Override
      protected void onPostExecute(Integer[] res) {
         progressDialog.dismiss();
         ...
      }
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store