Autore Topic: AsyncTask genera una runtime exception: Looper.prepare() not called  (Letto 1014 volte)

Offline Gianluca

  • Nuovo arrivato
  • *
  • Post: 19
  • Respect: +2
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S-II (i9100)
  • Sistema operativo:
    Windows 8
Ho questo codice molto semplice (scritto seguendo le linee guida di questo tutorial):
Codice (Java): [Seleziona]
package com.example.miopackage;

// import vari da android.*

import com.miopackage.core.MiaClasse;

public class MainActivity extends Activity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
               
        }
       
        private class MiaClasseTask extends AsyncTask<String,String,String>  {
              @Override
              protected String doInBackground(String... params) {
                  MiaClasse sessione = new MiaClasse("email", "password");
                  showToast(sessione.isAuthorized());
                  return ""; // giusto per ricordarmi che posso ritornare un output
              }
              @Override
              protected void onProgressUpdate(String... values) {
              }
              @Override
              protected void onPostExecute(String result) {      
              }
           }
       
        public void doSomething(View v) { // metodo relativo all'onClick di un bottone presente in View
                // Creates and starts AsyncTask
                MiaClasseTask task = new MiaClasseTask();
                task.execute();
        }
       
        private void showToast(String str) {
                Toast tempMessage = Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT); tempMessage.show();
        }

}

che genera questo errore:

Codice: [Seleziona]
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Ora, MiaClasse() è una classe che si collega ad un servizio web gestito da SAML, ne effettua il login e ne gestisce il reperimento dei sorgenti protetti.
isAuthorized() è un metodo scritto per verificare se le credenziali sono corrette. L'errore viene generato al momento del login, nella fase di invio dei dati via POST.
Infatti (questo è un estratto dei log delle operazioni principali):
Codice: [Seleziona]
04-04 20:46:34.142: I/System.out(1519): (1) - get IDP credentials
04-04 20:46:38.103: I/System.out(1519): (2.a) - get SAML request from the SP
04-04 20:46:38.552: I/System.out(1519): (2.b) - bounce SAML request to the IP
04-04 20:46:50.792: I/System.out(1519): (3) - login
04-04 20:46:51.152: W/dalvikvm(1519): threadid=12: thread exiting with uncaught exception (group=0x409961f8)
04-04 20:46:51.443: E/AndroidRuntime(1519): FATAL EXCEPTION: AsyncTask #1

Se conoscete un po' il progetto SAML, potete notare che si ferma alla fase del login, durante la procedura di POST.

Ho fatto una lunga ricerca sul blog, e gran parte dei thread non mi sono stati utili: Problema con Looper - Android Developers Italia e temporizzazione - Android Developers Italia non avevano risposte, e soprattutto non sembravano del tutto inerenti al caso mio.
Risultato di processo in background - Android Developers Italia propone addirittura di usare come soluzione proprio ciò che ho usato nel mio codice (AsyncTask). Non molto di aiuto...


Ci sarebbe qualche buon anima in grado di spiegarmi la relazione tra AsyncTask e looper.prepare()?


Ho letto questo topic Http Get - Android Developers Italia e sembra che il motivo stia nel fatto che istanzio più handlers in AsyncTask, che può gestirne solo uno. Ma non è vero! MiaClasse è semplicemente un package che fa alcune richieste HttpURLConnection() in sequenza, e basta. Tutte richieste sequenziali, semplici semplici. Inoltre è un package completamente estraneo ad Android, l'ho scritto da e per console e poi l'ho importato nel progetto, successivamente, senza alcuna modifica.

EDIT:
Dimenticavo le info di base, nel caso potesse essere utile: è un codice fatto girare su ICS (Google APIs, level 14), SDK aggiornato, su Eclipse - Windows 8.

Post unito: 04 Aprile 2013, 23:31:07 CEST
Continuando le ricerche, in questo topic ho trovato
Codice: [Seleziona]
95% of the time when you get the Looper error, what it really means is you need to move part of your code to the UI thread, in Asynctask this means moving it to either onPostExecute or onProgressUpdate.

Il punto dunque diventa: che genere di istuzioni native Java (praticamente tutte HttpURLRequest(), per inciso) hanno bisogno di essere fatte girare nell'UI thread?

Post unito: 04 Aprile 2013, 23:50:22 CEST
Got it! (thx to this Android looper.prepare() - Stack Overflow)

È lo showToast che ha bisogno della UI!
Codice (Java): [Seleziona]
              @Override
              protected String doInBackground(String... params) {
                  MiaClasse sessione = new MiaClasse("email", "password");
                  return sessione.isAuthorized()+"";
              }

              //..

              public void doSomething(View v) {
                      // Creates and start AsyncTask
                      MiaClasseTask task = new MiaClasseTask();
                      try { showToast(task.execute().get()); } catch (Exception e) {};
              }
« Ultima modifica: 04 Aprile 2013, 23:50:23 CEST da Gianluca, Reason: Merged DoublePost »

Offline lorux

  • Utente junior
  • **
  • Post: 97
  • Respect: +12
    • Google+
    • lor.catalano
    • Mostra profilo
  • Dispositivo Android:
    Galaxy S2
  • Sistema operativo:
    Windows
Re:AsyncTask genera una runtime exception: Looper.prepare() not called
« Risposta #1 il: 05 Aprile 2013, 08:49:48 CEST »
0
scusa eh,al posto di fare try/catch a caso,basta che al doinbackground fai tornare la risposta di isauthorized,poi showtoast lo chiami nell'onpostexecute

edit:e consiglio,non fare mai .execute().get(),stai eseguendo una task asincrona,se usi .get() il main thread aspetta che la task sia finita per continuare,quindi si perde l'asincronia
« Ultima modifica: 05 Aprile 2013, 08:52:14 CEST da lorux »

Offline Gianluca

  • Nuovo arrivato
  • *
  • Post: 19
  • Respect: +2
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S-II (i9100)
  • Sistema operativo:
    Windows 8
Re:AsyncTask genera una runtime exception: Looper.prepare() not called
« Risposta #2 il: 05 Aprile 2013, 10:30:13 CEST »
0
Veramente molto gentile. In effetti mi ero totalmente dimenticato per strada il onPostExecute. Thanks a lot.

(magari saresti addirittura in grado di darmi una risposta qui... chissà :P android - Publish progress from an external class during Async Task? - Stack Overflow)

Offline lorux

  • Utente junior
  • **
  • Post: 97
  • Respect: +12
    • Google+
    • lor.catalano
    • Mostra profilo
  • Dispositivo Android:
    Galaxy S2
  • Sistema operativo:
    Windows
Re:AsyncTask genera una runtime exception: Looper.prepare() not called
« Risposta #3 il: 05 Aprile 2013, 10:42:58 CEST »
0
vuoi capire come creare un'asynctask in un file a parte e non all'interno della classe dell'activity?

Offline Gianluca

  • Nuovo arrivato
  • *
  • Post: 19
  • Respect: +2
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S-II (i9100)
  • Sistema operativo:
    Windows 8
Re:AsyncTask genera una runtime exception: Looper.prepare() not called
« Risposta #4 il: 05 Aprile 2013, 14:31:46 CEST »
0
No, molto più semplicemente (e più "complicatamente") chiamare il metodo publishProgress() da un package esterno...

Offline lorux

  • Utente junior
  • **
  • Post: 97
  • Respect: +12
    • Google+
    • lor.catalano
    • Mostra profilo
  • Dispositivo Android:
    Galaxy S2
  • Sistema operativo:
    Windows
Re:AsyncTask genera una runtime exception: Looper.prepare() not called
« Risposta #5 il: 05 Aprile 2013, 15:15:35 CEST »
0
eh ma publishProgress è un metodo di asyncTask,tra l'altro protected,quindi non puoi accederci se non dall'asynctask stessa,non avrebbe neanche senso chiamarlo dall'esterno,che devi fare di preciso?

Offline Gianluca

  • Nuovo arrivato
  • *
  • Post: 19
  • Respect: +2
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S-II (i9100)
  • Sistema operativo:
    Windows 8
Re:AsyncTask genera una runtime exception: Looper.prepare() not called
« Risposta #6 il: 05 Aprile 2013, 15:22:19 CEST »
0
Eh, è proprio questo il problema... (/ot/ dov'è il thx button in questo forum?  :D)

Ho una serie di logs, generati in maniera sequenziale da isAuthorized(). Per capirci

Codice (Java): [Seleziona]
public Boolean isAuthorized() {
    // some stuff
    log("mi sto connettendo");
    // other stuff
    log("mi sono connesso, ora sto facendo il login...")
    //....
}

Siccome sono esterni, non posso spedirli a publishProgress(), ma d'altra parte la tempistica è il vero fulcro della questione - sennò che logs sono? - quindi non so davvero come fare. Mi sa che a questo punto l'unica è prendere tutto il package e includerlo in unico file, Login.java, che sarà un'activity. Peccato però... speravo di riuscire a tenere i sorgenti separati, così da facilitare la manutenzione...

Offline lorux

  • Utente junior
  • **
  • Post: 97
  • Respect: +12
    • Google+
    • lor.catalano
    • Mostra profilo
  • Dispositivo Android:
    Galaxy S2
  • Sistema operativo:
    Windows
Re:AsyncTask genera una runtime exception: Looper.prepare() not called
« Risposta #7 il: 05 Aprile 2013, 15:58:56 CEST »
0
vabbè ma dentro a isAuthorized che fà?
se puoi modificare l'isAuthorized in isAuthorized(this) puoi provare a creare un metodo pubblico nell'asynctask che a sua volta chiama il publishProgress,e dentro l'isauthorized chiami quel metodo pubblico ogni volta che devi mostrare il log diverso.
non so se funzionerà però..


il tasto thanks è nell'intestazione del post in alto a destra XD

Offline Gianluca

  • Nuovo arrivato
  • *
  • Post: 19
  • Respect: +2
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S-II (i9100)
  • Sistema operativo:
    Windows 8
Re:AsyncTask genera una runtime exception: Looper.prepare() not called
« Risposta #8 il: 05 Aprile 2013, 16:03:43 CEST »
0
Mah, io non lo vedo. Forse perché è un rating system serio tale per cui devo superare un certo numero di posts (10?).

Anyway...

L'avevo pensato anche io, ma non sarebbe generico. Utterly tailored for that AsyncTask.
Comunque, ragionandoci un po' su, non credo di aver bisogno di molte altre classi che facciano il display dei log del login. Ergo... potrebbe funzionare! :)
Provo e riporto ;)

Post unito: 05 Aprile 2013, 16:14:43 CEST
Ha funzionato!!

Codice (Java): [Seleziona]
       
// MyClass
import LoginLanding.MyClassTask mThreadReference = null;

// some stuff
        public void log(String str) {
                if (mThreadReference==null) {
                        SAMLTools.log(str);
                } else {
                        mThreadReference.doProgress("");
                }
        }

Codice (Java): [Seleziona]
public class LoginLanding extends Activity {
        // stuff

        public class MyClassTask extends AsyncTask<String,String,String>  {
                // bla bla bla
                public void doProgress(String str) {
                        // do something
                }
        }
}

Grazie mille! :D
« Ultima modifica: 05 Aprile 2013, 16:14:43 CEST da Gianluca, Reason: Merged DoublePost »

Offline lorux

  • Utente junior
  • **
  • Post: 97
  • Respect: +12
    • Google+
    • lor.catalano
    • Mostra profilo
  • Dispositivo Android:
    Galaxy S2
  • Sistema operativo:
    Windows
Re:AsyncTask genera una runtime exception: Looper.prepare() not called
« Risposta #9 il: 05 Aprile 2013, 16:15:19 CEST »
0
boh forse mi confondo io con thanks del post,non lo soXD

e allora tieni 2 metodi isAuthorized,uno con e uno senza this, e se il this c'è allora l'asynctask deve prevedere quel metodo pubblico per loggare,altrimenti se il this non c'è non logga un caiser

Offline Gianluca

  • Nuovo arrivato
  • *
  • Post: 19
  • Respect: +2
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S-II (i9100)
  • Sistema operativo:
    Windows 8
Re:AsyncTask genera una runtime exception: Looper.prepare() not called
« Risposta #10 il: 05 Aprile 2013, 16:16:35 CEST »
0
Ho risolto inizializzando la variabile a nulla, e creando due diversi costruttori. Praticamente la stessa cosa, presa da due lati diversi :) (see above)

Grazie ancora, appena capisco come aumentarti la rep, lo faccio  O:-)