Autore Topic: Esecuzione asincrona di un metodo  (Letto 1327 volte)

Offline enos

  • Nuovo arrivato
  • *
  • Post: 28
  • Respect: 0
    • Mostra profilo
Esecuzione asincrona di un metodo
« il: 15 Ottobre 2010, 12:59:18 CEST »
0
Ciao a tutti,
posto in questa sezione poichè il "cuore" del problema credo si risolva con un approccio multithreading...

Vi spiego: ho un'interfaccia grafica che devo aggiornare con dei dati che vengono periodicamente presi da un database da un metodo Update().
Siccome il metodo Update() è piuttosto lento ho pensato di eseguirlo in modo asincrono; per farlo ho seguito questo esempio.
Vi posto lo "scheletro" del mio codice:

Codice (Java): [Seleziona]
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        [ . . . ]
        StartUpdate();
    }

final Handler handler=new Handler();
final Runnable r = new Runnable()
{
   public void run()
   {
          sincronizza();
   }
};

public void Update() {
        // Costruisce il Vector newAmici; il Vector è composto da oggetti che contengono una ImageView
}

public void StartUpdate(){
       
        Thread t = new Thread(){
               public void run()
       {
                       Update();
                       handler.post(r);
               }
       };
       t.start();
}

private synchronized void aggiornaSchermata() {
       // lavora sul Vector Amici
}
private synchronized void sincronizza() {
       // aggiorna il vettore degli Amici
       Amici=newAmici;
}

Il problema è che Update() deve popolare un Vector con oggetti che contengono delle ImageView. Nonostante non le aggiunga alla UI (a questo ci pensa il metodo sincrono aggiornaSchermata), la sua esecuzione manda in crash l'applicazione.

Qualcuno ha idea di come possa risolvere il problema?

Grazie mille  :-)

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:Esecuzione asincrona di un metodo
« Risposta #1 il: 15 Ottobre 2010, 13:30:13 CEST »
0
Quando ci sono dei crash è bene postare il logcat, in questo modo andiamo alla ceca!

In ogni caso penso che il problema sia un accesso simultaneo alla variabile Vector, che non puoi fare. Usa un ArrayList.

Inutile mettere synchronized in quei due metodi. Li usi per assegnare la variabile, ma non per la lettura. Quindi hai accesso simultaneo.

Sai che con il comando Amici=newAmici; non stai ricreando il vettore ma stai puntando sempre alla stessa variabile? Quindi pensi che lavori con una mentre aggiorni l'altra nel ciclo Update, ma non è cosi!

In generale: lavora con un solo vettore (meglio un ArrayList) ed usa quello per tutto senza scambi di variabili. La funzione sincronizza la vedo inutile, dall'handler chiama direttamente aggiornaSchermata facendo il ciclo sull'ArrayList.

In ogni caso, per come la vedo io ha sbagliato l'approccio.
Da quello che vedo, il vector è una variabile di model, mentre tu la usi come una variabile di view. Nel vettore non salvare l'ImageView ma il dato puro (probabilmente l'indirizzo dell'immagine). L'ImageView la crei una volta e la vai aggiornando nel metodo aggiornaSchermata impostando semplicemente la url che prendi dal vettore (inoltre, se la url non è cambiata, non l'aggiorni affatto, aumentando le prestazioni dell'applicazione).

Altri dati non posso darteli non vedendo il codice.

Offline enos

  • Nuovo arrivato
  • *
  • Post: 28
  • Respect: 0
    • Mostra profilo
Re:Esecuzione asincrona di un metodo
« Risposta #2 il: 15 Ottobre 2010, 15:09:42 CEST »
0
Ciao Marco,
innanzitutto grazie per la risposta. Evidentemente devo aver commesso diversi errori... provo ad affrontare i vari punti che mi hai proposto:

In ogni caso penso che il problema sia un accesso simultaneo alla variabile Vector, che non puoi fare. Usa un ArrayList.
L'uso di due Vector (Amici e newAmici) è proprio per evitare conflitti tra le operazioni svolte da Update() e da aggiornaSchermata().


Inutile mettere synchronized in quei due metodi. Li usi per assegnare la variabile, ma non per la lettura. Quindi hai accesso simultaneo.
sincronizza() modifica l'area puntata da Amici, mentre aggiornaSchermata() ne legge il contenuto.

Sai che con il comando Amici=newAmici; non stai ricreando il vettore ma stai puntando sempre alla stessa variabile? Quindi pensi che lavori con una mentre aggiorni l'altra nel ciclo Update, ma non è cosi!

In generale: lavora con un solo vettore (meglio un ArrayList) ed usa quello per tutto senza scambi di variabili. La funzione sincronizza la vedo inutile, dall'handler chiama direttamente aggiornaSchermata facendo il ciclo sull'ArrayList.
newAmici viene restituito ogni volta da un metodo che crea un nuovo Vector e lo popola: l'area di memoria è quindi diversa di volta in volta. Creo i newAmici e con Amici=newAmici punto al nuovo Vector, in modo da aggiornare la schermata con i nuovi dati. Sbaglio?
La sincronizzazione è per evitare che aggiornaSchermata() si trovi a lavorare su Amici mentre sincronizza() modifica l'area di memoria da esso puntata.

In ogni caso, per come la vedo io ha sbagliato l'approccio.
Da quello che vedo, il vector è una variabile di model, mentre tu la usi come una variabile di view. Nel vettore non salvare l'ImageView ma il dato puro (probabilmente l'indirizzo dell'immagine). L'ImageView la crei una volta e la vai aggiornando nel metodo aggiornaSchermata impostando semplicemente la url che prendi dal vettore (inoltre, se la url non è cambiata, non l'aggiorni affatto, aumentando le prestazioni dell'applicazione).
Il Vector contiene degli oggetti della classe Amico: ogni amico, oltre ai soliti dati (nome, cognome, etc...), possiede anche la sua ImageView, che in questo modo non deve essere ricostruita ad ogni aggiornamento di schermata. (Update viene eseguito ogni tot secondi, aggiornaSchermata viene eseguito con frequenza molto più alta).

Grazie ancora per l'attenzione... e scusa l'inesperienza!  :D

Offline Ricky`

  • Amministratore
  • Utente storico
  • *****
  • Post: 3489
  • Respect: +507
    • Github
    • Google+
    • rciovati
    • Mostra profilo
Re:Esecuzione asincrona di un metodo
« Risposta #3 il: 15 Ottobre 2010, 21:02:17 CEST »
0
Beh non sie stato molto dettagliato nella spiegazione percui non saprei effettivamente consigliarti un approccio particolare.
Sappi comunque che esistono particolari implementazioni dell'interfaccia List che sono thread-safe e che quindi permettono di lavorare in situazioni di concorrenza senza nessun problema. Per maggiori informazioni basta una bella googlata :)

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:Esecuzione asincrona di un metodo
« Risposta #4 il: 15 Ottobre 2010, 22:39:46 CEST »
0
sincronizza() modifica l'area puntata da Amici, mentre aggiornaSchermata() ne legge il contenuto.

Si, ma nessuno ti assicura che questi due metodi vengono chiamati in modo indipendente. Mentre uno modifica l'altro può contemporaneamente leggere!

Il Vector contiene degli oggetti della classe Amico: ogni amico, oltre ai soliti dati (nome, cognome, etc...), possiede anche la sua ImageView, che in questo modo non deve essere ricostruita ad ogni aggiornamento di schermata. (Update viene eseguito ogni tot secondi, aggiornaSchermata viene eseguito con frequenza molto più alta).

Ma se dici che Vector viene creato ex-novo, come fa l'ImageView ad essere sempre la stessa...

Inizia ad essere difficile risponderti senza vedere del codice meno astratto!