JavascriptProva

lunedì 20 giugno 2016

Un modo di arrestare il loop dei services che si chiamano a vicenda.

Ora devo vedere come stoppare i due Services che si rincorrono.

Se distruggo tutti e due nello stesso tempo cosa accads?

MainActivity:
  button.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    stopService(new Intent(getApplicationContext(),Alfa.class));
    stopService(new Intent(getApplicationContext(),Beta.class));
   }
  });
Non funziona. Ho sempre quel succedersi indiavolato di giri viziosi fra l'uno e l'altro Service.



Ho risolto in questo modo: ho una variabile globale booleana chiamata stop dichiarata in una classe chiamata Globals:
public class Globals {
 public static boolean stop=false;
}
e pongo la condizione a ognuno dei due Services, per chiamare l'altro, che la variabile sia false:

Alfa:
public class Alfa extends Service{
 
 @Override
 public int onStartCommand(Intent intent, int flags, int startUI){
  Log.v("ALFA","ONSTARTCOMMAND");
  stopSelf();
  Log.v("ALFA","/ ONSTARTCOMMAND");
  return Service.START_NOT_STICKY;
 }
 
 @Override
 public void onDestroy(){
  Log.v("ALFA","ONDESTROY");
  if(Globals.stop==false)startService(new Intent(this,Beta.class));
  Log.v("ALFA","/ ONDESTROY");
  super.onDestroy();
 }

 @Override
 public IBinder onBind(Intent intent) {
  // TODO Auto-generated method stub
  return null;
 }
 
}


Beta:
public class Beta extends Service{

 @Override
 public int onStartCommand(Intent intent, int flags, int startUI){
  Log.v("BETA","ONSTARTCOMMAND");
  Log.e("BETA","Esecuzione del compito stabilito");
  stopSelf();
  Log.v("BETA","/ ONSTARTCOMMAND");
  return Service.START_NOT_STICKY; 
 }
 
 @Override
 public void onDestroy(){
  Log.v("BETA","ONDESTROY");
  if(Globals.stop==false)startService(new Intent(this,Alfa.class));
  Log.v("BETA","/ ONDESTROY");
  super.onDestroy();
 }
 
 @Override
 public IBinder onBind(Intent intent) {
  // TODO Auto-generated method stub
  return null;
 }
 
}
Così facendo, pare funzioni egregiamente, ponendo che in MainActivity il pulsante "Stop" dia alla variabile il valore true
  button.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    Globals.stop=true;
    Log.d("STOP","TRUE");
   }
  });
...ovviamente, facendo in modo che il pulsante Start reimposti la variabile a false:
  bttStart.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    Globals.stop=false;
    intent=new Intent(getApplicationContext(),Alfa.class); 
    startService(intent);
    
   }
  });
E cavoli, funziona!
Metto un "marker" che mi dia il valore della variabile nel momento in cui viene impostata a true e mi analizzo un po' la cosa in LogCat:
06-20 18:57:45.648: V/ALFA(1873): ONDESTROY
06-20 18:57:45.658: V/ALFA(1873): / ONDESTROY
06-20 18:57:45.658: V/BETA(1873): ONSTARTCOMMAND
06-20 18:57:45.658: E/BETA(1873): Esecuzione del compito stabilito
06-20 18:57:45.658: V/BETA(1873): / ONSTARTCOMMAND
06-20 18:57:45.658: D/STOP(1873): TRUE
06-20 18:57:45.658: V/BETA(1873): ONDESTROY
06-20 18:57:45.658: V/BETA(1873): / ONDESTROY
Qui la variabile è stata impostata a TRUE dopo che Beta ha eseguito onStartCommand e ha chiamato onDestroy: arrivato a onDestroy il codice trova la variabile TRUE e non chiama Alfa, così il ciclo si interrompe.

06-20 19:00:08.708: V/BETA(1873): / ONSTARTCOMMAND
06-20 19:00:08.708: V/BETA(1873): ONDESTROY
06-20 19:00:08.718: V/BETA(1873): / ONDESTROY
06-20 19:00:08.718: V/ALFA(1873): ONSTARTCOMMAND
06-20 19:00:08.718: V/ALFA(1873): / ONSTARTCOMMAND
06-20 19:00:08.718: D/STOP(1873): TRUE
06-20 19:00:08.728: V/ALFA(1873): ONDESTROY
06-20 19:00:08.728: V/ALFA(1873): / ONDESTROY
Alfa ha eseguito onStartCommand chiamando onDestroy, ma nel frattempo la variabile globale è diventata TRUE, e così il codice di onDestroy non chiama più Beta e il ciclo si interrompe.

06-20 19:01:24.222: V/ALFA(1873): ONDESTROY
06-20 19:01:24.222: V/ALFA(1873): / ONDESTROY
06-20 19:01:24.232: D/STOP(1873): TRUE
06-20 19:01:24.232: V/BETA(1873): ONSTARTCOMMAND
06-20 19:01:24.232: E/BETA(1873): Esecuzione del compito stabilito
06-20 19:01:24.232: V/BETA(1873): / ONSTARTCOMMAND
06-20 19:01:24.242: V/BETA(1873): ONDESTROY
06-20 19:01:24.242: V/BETA(1873): / ONDESTROY
Ecco, questa è più interessante: Alfa ha appena chiamato Beta, e nel frattempo la variabile diventa TRUE: dato che la chiamata è già partita, il compito viene comunque eseguito, quindi si va a onDestroy e Beta non chiama più Alfa dato che incontra un TRUE.
Se io voglio interrompere l'esecuzione del programma nel preciso momento in cui schiaccio il pulsante Stop, ossia nel preciso momento in cui la variabile diventa TRUE, questo non va più bene. In tempi rapidi, la differenza non si nota, ma se io devo inserire un Timer in modo da far diventare questi tempi minuti od ore, allora il problema emerge, perché potrei avere la cessazione dell'attività del programma anche molte ore dopo averlo interrotto con il pulsante Stop

Studiamo una soluzione...

Non mi piace molto perché mi sembrerebbe più elegante una soluzione con una sola verifica di Globals.stop, ma dovrebbe funzionare:

Beta:
 public int onStartCommand(Intent intent, int flags, int startUI){
  Log.v("BETA","ONSTARTCOMMAND");
  if(Globals.stop==false)Log.e("BETA","Esecuzione del compito stabilito");
  stopSelf();
  Log.v("BETA","/ ONSTARTCOMMAND");
  return Service.START_NOT_STICKY; 
 }
Ecco, dopo vari tentativi, TRUE è ricapitato nel posto che mi interessa analizzare:
06-20 19:10:09.614: V/ALFA(5123): ONSTARTCOMMAND
06-20 19:10:09.614: V/ALFA(5123): / ONSTARTCOMMAND
06-20 19:10:09.614: V/ALFA(5123): ONDESTROY
06-20 19:10:09.624: V/ALFA(5123): / ONDESTROY
06-20 19:10:09.654: D/STOP(5123): TRUE
06-20 19:10:09.654: D/dalvikvm(5123): GC_EXPLICIT freed 501K, 47% free 6875K/12928K, paused 2ms+4ms, total 32ms
06-20 19:10:09.674: V/BETA(5123): ONSTARTCOMMAND
06-20 19:10:09.674: V/BETA(5123): / ONSTARTCOMMAND
06-20 19:10:09.674: V/BETA(5123): ONDESTROY
06-20 19:10:09.674: V/BETA(5123): / ONDESTROY
Così facendo, viene eseguito ONSTARTCOMMAND ma senza che venga eseguito il compito specifico.
Compare quel codice che non riesco a capire...

06-20 19:12:37.989: V/ALFA(5123): ONDESTROY
06-20 19:12:37.999: V/ALFA(5123): / ONDESTROY
06-20 19:12:37.999: D/STOP(5123): TRUE
06-20 19:12:37.999: V/BETA(5123): ONSTARTCOMMAND
06-20 19:12:37.999: V/BETA(5123): / ONSTARTCOMMAND
06-20 19:12:38.009: V/BETA(5123): ONDESTROY
06-20 19:12:38.009: V/BETA(5123): / ONDESTROY
Adesso è ricapitato nello stesso punto, ma non appare nulla... Non so. Forse sarò in condizione di capirlo in tempi futuri...

Comunque, questo sistema FUNZIONA!

Nessun commento:

Posta un commento