Autore Topic: Chiusura progress bar -> terminare thread e tornare indietro: Come fare?!  (Letto 1440 volte)

Offline OmarLuigi

  • Nuovo arrivato
  • *
  • Post: 20
  • Respect: +1
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Tab
  • Sistema operativo:
    Windows 7
Ciao a tutti..
Avvio un thread che fa un lavoro pesante (scaricamento dati da web service) ed intanto visualizzo una progress bar. Tutto bene.
Problema: premendo BACK vorrei che 1) ovviamente si chiudesse la progress 2) terminasse il thread avviato 3) il programma tornasse alla view precedente
Per ora sono risucito a  hiudere la progress... Ma terminare il thread o tornare alla view precedente no... Penso che il mio codice sia concettualmente errato perchè ha un comportamento strano.

Vi posto il pezzo di riferimento:

Codice (Java): [Seleziona]
    protected Dialog onCreateDialog(int id)
    {   switch(id)
        {       [...]
                case PROGRESS_DIALOG_PROJECTS:
                progressDialog=ProgressDialog.show(ProjectMain.this,"","Scaricamento progetti...");
                progressDialog.setCancelable(true);
                progressDialog.setOnCancelListener
                                (       new OnCancelListener()
                                        {       public void onCancel(DialogInterface dialog)
                                                {       ProjectRequest.stop(); // TEORICAMENTE DOVREBBE TERMINARE IL THREAD!!
//E PER TORNARE INDIETRO!?
                                                }
                                        }
                                );
            return      progressDialog;
                default: return null;
        }
    }

Questo è quanto spero nel vostro aiuto... E' un progetto aziendale (sono un tirocinante di ing informatica) e mi manca solo la risoluzione di questo back per terminarlo!

Grazie in anticipo =)



Offline Ricky`

  • Amministratore
  • Utente storico
  • *****
  • Post: 3489
  • Respect: +506
    • Github
    • Google+
    • rciovati
    • Mostra profilo
Re:Chiusura progress bar -> terminare thread e tornare indietro: Come fare?!
« Risposta #1 il: 06 Giugno 2011, 11:01:14 CEST »
0
Per tornare indietro ProjectMain.this.finish()

Per stoppare il thread prova il metodo Thread.interrupt(), nella documentazione c'è scritto chiaramente che Thread.stop() è  deprecato e potrebbe non funzionare come ti aspetti.

PS: Perchè formatti il codice secondo le convenzioni di C#? :)

Offline OmarLuigi

  • Nuovo arrivato
  • *
  • Post: 20
  • Respect: +1
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Tab
  • Sistema operativo:
    Windows 7
Re:Chiusura progress bar -> terminare thread e tornare indietro: Come fare?!
« Risposta #2 il: 06 Giugno 2011, 12:19:04 CEST »
0
allora...
Ho modificato così il codice:


Codice (Java): [Seleziona]
                case PROGRESS_DIALOG_PROJECTS:
                progressDialog=ProgressDialog.show(ProjectMain.this,"","Scaricamento progetti...");
                progressDialog.setCancelable(true);
                progressDialog.setOnCancelListener
                                (       new OnCancelListener()
                                        {       public void onCancel(DialogInterface dialog)
                                                {       Thread moribund = ProjectRequest;
                                                        ProjectRequest= null;
                                                        moribund.interrupt();
                                                        ProjectMain.this.finish();
                                                }
                                        }
                                );
            return      progressDialog;
                default: return null;




Chiude la progress, torna indietro... Ma penso che il Thread non sia terminato correttamente... Infatti dopo essere tornato indietro crasha!
Ho provato a debuggare... Ma non crasha in nessuna delle istruzioni che riportato sopra...
Comunque questo è il LogCat... Catturato da quando clicco back a quando crasha...


06-06 12:17:00.920: DEBUG/dalvikvm(8157): GC_FOR_MALLOC freed 22840 objects / 1035392 bytes in 33ms
06-06 12:17:02.090: ERROR/ShutdownThread(2490): IsShutDownStarted()
06-06 12:17:02.090: INFO/KeyInputQueue(2490): Input event
06-06 12:17:02.090: DEBUG/KeyInputQueue(2490): screenCaptureKeyFlag setting 1
06-06 12:17:02.092: VERBOSE/WindowManager(2490): Dsptch to Window{485eeaa8 omar.MustProgetti/omar.MustProgetti.ProjectMain paused=false}
06-06 12:17:02.092: WARN/KeyCharacterMap(8157): No keyboard for id 0
06-06 12:17:02.092: WARN/KeyCharacterMap(8157): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
06-06 12:17:02.252: ERROR/ShutdownThread(2490): IsShutDownStarted()
06-06 12:17:02.252: INFO/KeyInputQueue(2490): Input event
06-06 12:17:02.252: DEBUG/KeyInputQueue(2490): screenCaptureKeyFlag setting 0
06-06 12:17:02.260: VERBOSE/VibratorService(2490): vibrateImmVibe: 13, magnitude: -1
06-06 12:17:02.260: VERBOSE/VibratorService(2490): setVibeStrength = 10000
06-06 12:17:02.260: VERBOSE/WindowManager(2490): Dsptch to Window{485eeaa8 omar.MustProgetti/omar.MustProgetti.ProjectMain paused=false}
06-06 12:17:02.639: DEBUG/dalvikvm(8157): GC_FOR_MALLOC freed 47522 objects / 2013424 bytes in 44ms
06-06 12:17:03.229: DEBUG/AndroidRuntime(8157): Shutting down VM
06-06 12:17:03.229: WARN/dalvikvm(8157): threadid=1: thread exiting with uncaught exception (group=0x4001d7d0)
06-06 12:17:03.233: ERROR/AndroidRuntime(8157): FATAL EXCEPTION: main
06-06 12:17:03.233: ERROR/AndroidRuntime(8157): java.lang.IllegalArgumentException: no dialog with id 1 was ever shown via Activity#showDialog
06-06 12:17:03.233: ERROR/AndroidRuntime(8157):     at android.app.Activity.missingDialog(Activity.java:2590)
06-06 12:17:03.233: ERROR/AndroidRuntime(8157):     at android.app.Activity.dismissDialog(Activity.java:2575)
06-06 12:17:03.233: ERROR/AndroidRuntime(8157):     at omar.MustProgetti.ProjectMain$5.handleMessage(ProjectMain.java:103)
06-06 12:17:03.233: ERROR/AndroidRuntime(8157):     at android.os.Handler.dispatchMessage(Handler.java:99)
06-06 12:17:03.233: ERROR/AndroidRuntime(8157):     at android.os.Looper.loop(Looper.java:123)
06-06 12:17:03.233: ERROR/AndroidRuntime(8157):     at android.app.ActivityThread.main(ActivityThread.java:4627)
06-06 12:17:03.233: ERROR/AndroidRuntime(8157):     at java.lang.reflect.Method.invokeNative(Native Method)
06-06 12:17:03.233: ERROR/AndroidRuntime(8157):     at java.lang.reflect.Method.invoke(Method.java:521)
06-06 12:17:03.233: ERROR/AndroidRuntime(8157):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:871)
06-06 12:17:03.233: ERROR/AndroidRuntime(8157):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
06-06 12:17:03.233: ERROR/AndroidRuntime(8157):     at dalvik.system.NativeStart.main(Native Method)
06-06 12:17:03.237: WARN/ActivityManager(2490):   Force finishing activity omar.MustProgetti/.LogInMain
06-06 12:17:03.241: INFO/(2490): dumpmesg > /data/log/dumpstate_app_error.log
06-06 12:17:03.248: INFO/dumpstate(8168): begin
06-06 12:17:08.256: WARN/PowerManagerService(2490): Timer 0x7->0x3|0x3
06-06 12:17:08.260: INFO/PowerManagerService(2490): Ulight 7->3|0
06-06 12:17:14.596: DEBUG/VoldCmdListener(2372): asec list
06-06 12:17:15.858: INFO/dumpstate(8168): done
06-06 12:17:15.987: WARN/ActivityManager(2490): Activity pause timeout for HistoryRecord{482e1310 omar.MustProgetti/.LogInMain}
06-06 12:17:16.026: INFO/Launcher(2587): onResume(). mIsNewIntent : false
06-06 12:17:16.041: WARN/ActivityManager(2490): Launch timeout has expired, giving up wake lock!
06-06 12:17:16.116: INFO/Launcher(2587): Clearing the Status Bar lock in onResume function
06-06 12:17:16.120: DEBUG/StatusBar(2490): manageDisableList what=0x0 pkg=com.sec.android.app.twlauncher
06-06 12:17:16.123: ERROR/Launcher(2587): setWindowOpaque()
06-06 12:17:16.182: INFO/Launcher(2587): onResume() ended
06-06 12:17:16.659: ERROR/InfoAlarmWidget(2587): AllDay Event Count = 0
06-06 12:17:17.713: INFO/PowerManagerService(2490): Ulight 3->7|0
06-06 12:17:17.721: VERBOSE/WindowManager(2490): Delivering toWindow{485f3898 Siamo spiacenti! paused=false}
06-06 12:17:17.881: VERBOSE/WindowManager(2490): Delivering toWindow{485f3898 Siamo spiacenti! paused=false}
06-06 12:17:17.881: INFO/Process(8157): Sending signal. PID: 8157 SIG: 9
06-06 12:17:17.897: INFO/Launcher(2587): onWindowFocusChanged(true)
06-06 12:17:17.897: ERROR/Launcher(2587): setWindowOpaque()
06-06 12:17:18.057: INFO/ActivityManager(2490): Process omar.MustProgetti (pid 8157) has died.
06-06 12:17:18.057: INFO/WindowManager(2490): WIN DEATH: Window{484bfdd8 omar.MustProgetti/omar.MustProgetti.LogInMain paused=false}
06-06 12:17:18.057: INFO/WindowManager(2490): WIN DEATH: Window{4857bb08 Toast paused=false}

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:Chiusura progress bar -> terminare thread e tornare indietro: Come fare?!
« Risposta #3 il: 06 Giugno 2011, 12:44:46 CEST »
0
Il metodo interrupt() non interrompe istantaneamente il thread, consideralo come una richiesta di interruzione. Per cui immagino che il problema potrebbe sorgere dal fatto che subito dopo aver inviare la richiesta di interrupt, distruggi l'activity.

Come prima prova a bassissimo impatto, proverei ad attendere l'effettiva chiusura del thread prima di dare finish, una cosa del genere (che non mi piace, ma serve a capire se il problema è quello):

Codice (Java): [Seleziona]
moribund.interrupt();
while (moribund.isAlive()) { }
ProjectMain.this.finish();
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline OmarLuigi

  • Nuovo arrivato
  • *
  • Post: 20
  • Respect: +1
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Tab
  • Sistema operativo:
    Windows 7
Re:Chiusura progress bar -> terminare thread e tornare indietro: Come fare?!
« Risposta #4 il: 06 Giugno 2011, 17:57:38 CEST »
0
Grazie per la risposta Bradipao.

Codice (Java): [Seleziona]
Thread moribund = ProjectRequest;
ProjectRequest= null;
moribund.interrupt();
while (moribund.isAlive());
ProjectMain.this.finish();

Non crasha più, la Progress scampare e torna indietro correttamente senza crashare... Però il thread non termina! Lo so perchè l'ultima istruzione del thread è la visualizzazione di un toast... Ed essa avviene correttamente nella pagina in cui sono tornato indietro!
Per chiarire l'errore ho provato a sostituire il codice con questo

Codice (Java): [Seleziona]
//Thread moribund = ProjectRequest;
//ProjectRequest= null;
//moribund.interrupt();
while (ProjectRequest.isAlive());
ProjectMain.this.finish();

In cui mancano le istruzioni per la terminazio del Thread... Ed il risultato è lo stesso!!!

In breve: come chiudere un thread?! Finora i tentativi fatti con interrupt() e stop() sono falliti.

Grazie a tutti.



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:Chiusura progress bar -> terminare thread e tornare indietro: Come fare?!
« Risposta #5 il: 07 Giugno 2011, 08:01:27 CEST »
+1
In breve: come chiudere un thread?! Finora i tentativi fatti con interrupt() e stop() sono falliti.

Nella documentazione e nei tutorial che ho letto, chiudere un thread con stop() o interrupt() è sempre sconsigliato, perchè è come spegnere il computer staccando la spina: è grezzo e non sai mai cosa accade. Come implementato qua ( [medio] Introduzione ai Thread - Android Developers Italia ) è sempre meglio prevedere un metodo naturale per la chiusura del thread, cioè fare in modo che su preciso comando il thread esca naturalmente dal metodo run(), inserendo quindi nel codice stesso la possibilità di ricevere una richiesta di uscita.

Magari interrupt è usabilissimo, usatissimo e perfettamente funzionante, ma di sicuro il metodo sopra descritto è più elegante.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline teskio

  • Moderatore globale
  • Utente normale
  • *****
  • Post: 387
  • Respect: +118
    • Github
    • Google+
    • Mostra profilo
    • Skullab
  • Dispositivo Android:
    Cubot GT99 / SurfTab Ventos 10.1
  • Play Store ID:
    Skullab Software
  • Sistema operativo:
    windows 7 / ubuntu 12.04
Re:Chiusura progress bar -> terminare thread e tornare indietro: Come fare?!
« Risposta #6 il: 07 Giugno 2011, 10:14:03 CEST »
0
Di fatto però non sappiamo come hai implementato il metodo run() del tuo thread per "accettare" una richiesta di interrupt  :-P
Generalmente è sempre consigliabile far terminare il thread in modo ciclico, come consiglia bradipao, nel senso che se il tuo thread contiene al suo interno un loop (con while o con un for...etc) è necessario fare un check all'interno del loop stesso per controllare se l'utente abbia o meno interrotto il thread. Ad esempio per controllare se l'utente abbia generato una richiesta di interrupt(), all'interno del thread bisognerebbe verificare l'avvenuta richiesta con ad esempio Thread.interrupted(), e quindi gestire la chiusura del thread. Il metodo interrupt() potrebbe però generare eccezzioni se si tenta di interrompere un thread "bloccato", ad esempio attraverso Thread.sleep(). In questo caso va gestita l'eccezione InterruptedException.

Se però il thread è un ciclo unico, formato solo da istruzioni procedurali lineari di breve durata, la necessità di terminare il thread viene meno.
Ad esempio, se il metodo run() fosse scritto così :

Codice (Java): [Seleziona]
public void run(){
    if(Thread.interrupted())return ;
    String foo = "sono una stringa" ;
    int numberFoo = 10 ;
   // eccetera...
}

In questa situazione il controllo viene eseguito all'inizio e basta, bisogna essere mooolto rapidi a fermare il thread  :-P, quindi quello che ne deriverà è che il thread continuerà la sua "corsa" e terminerà naturalmente. ma se invece il metodo run() appare più così :

Codice (Java): [Seleziona]
public void run(){
   while(true){
        // fai qualcosa
       if(Thread.interrupted())break ;
    }
}

Allora in questo caso il thread potrà essere fermato e gestito, in quanto avverrà un controllo ciclico sull'interrupt.

Offline OmarLuigi

  • Nuovo arrivato
  • *
  • Post: 20
  • Respect: +1
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Tab
  • Sistema operativo:
    Windows 7
Re:Chiusura progress bar -> terminare thread e tornare indietro: Come fare?!
« Risposta #7 il: 08 Giugno 2011, 09:21:32 CEST »
0
Ecco com'è implementato il mio Thread:

Codice (Java): [Seleziona]
package omar.MustProgetti;
import java.io.IOException;
import omar.MustProgetti.R;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.AndroidHttpTransport;
import org.xmlpull.v1.XmlPullParserException;
import android.os.Handler;

class ProjectRequest extends Thread
{       private ProjectMain main;      
        private Handler HandlerRiempimento, HandlerTerminazione;
       
        String URL; String SOAP_ACTION; String NAMESPACE; String METHOD_NAME;
        int MSG_STRING;

        public ProjectRequest(Handler HandlerRiempimento, Handler HandlerTerminazione, ProjectMain main) //costruttore
        {       // salvo l'handler dei messaggi dell'activity chiamante
                this.HandlerRiempimento=HandlerRiempimento;
                this.HandlerTerminazione=HandlerTerminazione;
                this.main= main;
                URL = main.getResources().getString(R.string.URL_2);
                SOAP_ACTION = main.getResources().getString(R.string.SOAP_ACTION_2);
                NAMESPACE = main.getResources().getString(R.string.NAMESPACE_2);
                METHOD_NAME = main.getResources().getString(R.string.METHOD_NAME_2);
                MSG_STRING = main.getResources().getInteger(R.integer.MSG_STRING);
               

        }
       
        // avvio del thread
        public synchronized void start()
        {       super.start();
        }
       
        public void run()
        {       AndroidHttpTransport aht=new AndroidHttpTransport(URL); //dichiaro il client Http
                SoapSerializationEnvelope Envelope= new SoapSerializationEnvelope(SoapEnvelope.VER11); //dichiaro la busta Soap
                CreateEnvelope(Envelope); //creo busta SOAP
                try
                {       aht.call(SOAP_ACTION, Envelope); //invio la busta tramite il client http
                        SoapObject response = (SoapObject) Envelope.getResponse(); //ricevo la risposta
                        Parser(response);//parserizzo e inoltro                
                }
                catch (IOException e) { }
                catch (XmlPullParserException e) {      }
        }
       
        public void CreateEnvelope (SoapSerializationEnvelope Envelope)
        {       SoapObject Get = new SoapObject(NAMESPACE, METHOD_NAME); ////dichiaro il corpo interno
                Get.addProperty("TicketID", main.getTicketID());
                SoapObject Request = new SoapObject(NAMESPACE, METHOD_NAME); //dichiaro il corpo interno
                Get.addProperty("Request", Request);//incapsulo il corpo interno in quello esterno
               
                Request.addProperty("FamilyID", main.getFamilyID());
               
                Request.addProperty("Archivied", false);
                Request.addProperty("TemplateOnly",false);

                Envelope.setOutputSoapObject(Get); //impacchetto la richiesta nella busta
                Envelope.dotNet=true;//imposto la compatibilità con .Net
                Envelope.implicitTypes=true;//avverto la busta che conterrà elementi incapsulati (corpo interno -> corpo esterno)
        }  
       
        public void Parser(SoapObject response)
        {       SoapObject ProjectList= (SoapObject) response.getProperty("ProjectList");
                for(int i=0; i<ProjectList.getPropertyCount(); i++) //per ogni progetto, creo un nuovo oggetto myProject che lo rappresenta
                {       ProjectStructure Progetto= new ProjectStructure();
                        SoapObject clsProjectListItem= (SoapObject) ProjectList.getProperty(i);
                        String Family = clsProjectListItem.getProperty("Family").toString();
                        if(Family.equals("anyType{}")) Family="Senza famiglia";
                        Progetto.setFamily(Family);
                        Progetto.setID(clsProjectListItem.getProperty("ID").toString());
                        Progetto.setTitle(clsProjectListItem.getProperty("Title").toString());
                        Progetto.setLastModifyDateDesc(clsProjectListItem.getProperty("LastModifyDateDesc").toString());
                        HandlerRiempimento.obtainMessage(MSG_STRING, Progetto.toString().length(), -1, Progetto.toString()).sendToTarget(); //gli passo il progetto creato
                }
                HandlerTerminazione.obtainMessage().sendToTarget();
        }      
}


Ma quindi, se ho capito bene, all'interno di questo codice dovrei inserire un qualcosa per gestire l'interruzione vero? Diciamo un handler per le interruzioni...?!
Scusatemi ma è la prima volta che faccio una cosa del genere!