JavascriptProva

martedì 28 giugno 2016

Studio dello Stop per la mia applicazione per mezzo delle variabili globali

Shared preferences.
Mi servono per la mia applicazione.
Ma prima cerchiamo di renderla con le variabili globali...

Ecco, ho ripristinato il meccanismo di reciproca chiamata fra un Service e un'Activity.

Service di nome Timer:
 @Override
 public void onDestroy(){
  Log.d("TIMER","ONDESTROY");
  Intent intent=new Intent(this,Form.class);
  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  startActivity(intent);
  Log.d("TIMER","/ ONDESTROY");
  super.onDestroy();
 }


Activity di nome Form, alla pressione di un pulsante si ha l'istruzione finish() che rimanda a onDestroy().
 public void onDestroy(){
  startService(new Intent(this, Timer.class));
  super.onDestroy();
 }
Quest'ultima non è marcata. La marco e procedo allo studio dell'interruzione del ciclo.
 public void onDestroy(){
  Log.d("FORM","ONDESTROY");
  startService(new Intent(this, Timer.class));
  Log.d("FORM","/ ONDESTROY");
  super.onDestroy();
 }

Per il momento, c'è il richiamo immediato di Form da Timer, mentre il richiamo inverso è ritardato solo in quanto subordinato alla pressione del pulsante.
Ora inserisco un AlarmManager in Timer:
 @Override
 public void onDestroy(){
  Log.d("TIMER","ONDESTROY");
  Intent intent=new Intent(this,Form.class);
  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  pendingIntent=PendingIntent.getActivity(this, 0, intent, 0);
  alarmManager=(AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
  alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+5*1000, pendingIntent);
  Log.d("TIMER","/ ONDESTROY");
  super.onDestroy();
 }
L'ho impostato a 5 secondi.
Lo sperimento.

Ho dovuto fare qualche aggiustamento per correggere errori di distrazione e dovuti al fatto che non ricordavo bene la procedura...

Comunque alla fine funziona: l'Act Form appare dopo 5 secondi dalla prima pressione del pulsante Start e quindi si ripete sempre dopo 5 secondi dal suo tasto Invia.

Ora devo gestire lo stop, con le variabili globali.
Aggiungo questa riga:
 @Override
 public void onDestroy(){
  Log.d("TIMER","ONDESTROY");
  Intent intent=new Intent(this,Form.class);
  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  pendingIntent=PendingIntent.getActivity(this, 0, intent, 0);
  alarmManager=(AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
  alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+5*1000, pendingIntent);
  if(Globals.Stop==true)alarmManager.cancel(pendingIntent);
  Log.d("TIMER","/ ONDESTROY");
  super.onDestroy();
 }
e il codice per il pulsante che renda true la variabile globale Stop.
  bttStop.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    Globals.Stop=true;
    
   }
  });
Vediamo...

Per far ripartire il ciclo ci metto pure la variabile che ridiventa false con il pulsante Start:
  bttStart.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    Globals.Stop=false;
    startService(new Intent(getApplicationContext(),Timer.class));
    
   }
  });


Sperimento la cosa. Quando sono tornato sulla schermata Main, quella con i due pulsanti Start e Stop, se schiaccio Stop il ciclo successivo si ripete per una volta e quindi si stoppa definitivamente.
Evidentemente, una volta che alarmManager è "partito"; anche se viene cancellato, questo vale per il ciclo successivo.

Faccio un'altra prova: metto il Cancel direttamente dove sta senza condizioni...

 @Override
 public void onDestroy(){
  Log.d("TIMER","ONDESTROY");
  Intent intent=new Intent(this,Form.class);
  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  pendingIntent=PendingIntent.getActivity(this, 0, intent, 0);
  alarmManager=(AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
  alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+3*1000, pendingIntent);
  /*if(Globals.Stop==true)*/alarmManager.cancel(pendingIntent);
  Log.d("TIMER","/ ONDESTROY");
  super.onDestroy();
 }
Ecco: così facendo, il ciclo non parte affatto perché alarmManager viene cancellato "sul nascere".
Dunque il problema non è che il ciclo era già stato avviato quando viene richiesto il valore della variabile Stop, ma forse il fatto che la variabile Stop è ancora false fino a quando non si sia avviato Form.
Questo codice:
 @Override
 public void onDestroy(){
  Log.d("TIMER","ONDESTROY");
  Intent intent=new Intent(this,Form.class);
  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  pendingIntent=PendingIntent.getActivity(this, 0, intent, 0);
  alarmManager=(AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
  alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+3*1000, pendingIntent);
  if(Globals.Stop==true)alarmManager.cancel(pendingIntent);
  Log.d("STOP",""+Globals.Stop);
  Log.d("TIMER","/ ONDESTROY");
  super.onDestroy();
 }
...me lo prova:
06-28 14:13:39.367: D/TIMER(4762): ONSTARTCOMMAND
06-28 14:13:39.367: D/TIMER(4762): / ONSTARTCOMMAND
06-28 14:13:39.367: D/TIMER(4762): ONDESTROY
06-28 14:13:39.377: D/STOP(4762): false
06-28 14:13:39.377: D/TIMER(4762): / ONDESTROY
Ossia quando viene premuto il pulsante, Globals.Stop è ancora false.
Ma proseguendo ancora oltre...
06-28 14:13:39.367: D/TIMER(4762): ONSTARTCOMMAND
06-28 14:13:39.367: D/TIMER(4762): / ONSTARTCOMMAND
06-28 14:13:39.367: D/TIMER(4762): ONDESTROY
06-28 14:13:39.377: D/STOP(4762): false
06-28 14:13:39.377: D/TIMER(4762): / ONDESTROY
06-28 14:13:50.018: D/FORM(4762): ONDESTROY
06-28 14:13:50.018: D/FORM(4762): / ONDESTROY
06-28 14:13:50.038: D/TIMER(4762): ONSTARTCOMMAND
06-28 14:13:50.038: D/TIMER(4762): / ONSTARTCOMMAND
06-28 14:13:50.038: D/TIMER(4762): ONDESTROY
06-28 14:13:50.048: D/STOP(4762): true
06-28 14:13:50.048: D/TIMER(4762): / ONDESTROY
...si vede che al ciclo successivo la variabile è true e quindi il ciclo si ferma.

Dunque voglio vedere quando diventa true: mi marco a tale scopo anche Form...

public class Form extends Activity {

 Button button1, button2, button3, button4, button5;
 ImageView imageView;
 DBHelper dbHelper;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_form);
  Log.d("FORM","ONCREATE");
  Log.d("STOP",""+Globals.Stop);
  
  button1=(Button)findViewById(R.id.button1);
  button2=(Button)findViewById(R.id.button2);
  button3=(Button)findViewById(R.id.button3);
  button4=(Button)findViewById(R.id.button4);
  button5=(Button)findViewById(R.id.bttInvia);
  imageView=(ImageView)findViewById(R.id.imageView1);
  
  OnClickListener onClickListener=new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    if(v==button1) imageView.setImageResource(R.drawable.nonurgentenonimportante);
    if(v==button2) imageView.setImageResource(R.drawable.urgentenonimportante);
    if(v==button3) imageView.setImageResource(R.drawable.urgenteimportante);
    if(v==button4) imageView.setImageResource(R.drawable.nonurgenteimportante);
    button5.setVisibility(View.VISIBLE);
    
    
   }
  };
  
  button5.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    finish(); 
    
   }
  });
  button1.setOnClickListener(onClickListener);
  button2.setOnClickListener(onClickListener);
  button3.setOnClickListener(onClickListener);
  button4.setOnClickListener(onClickListener);

  Log.d("FORM","/ ONCREATE");

 }
 
 public void onDestroy(){
  Log.d("FORM","ONDESTROY");
  Log.d("STOP",""+Globals.Stop);
  startService(new Intent(this, Timer.class));
  Log.d("FORM","/ ONDESTROY");
  super.onDestroy();
 }


}
E riproviamo: interrogo il valore della variabile all'inizio di FORM ONCREATE e all'inizio di FORM ONDESTROY.

06-28 14:26:35.604: D/TIMER(9225): ONDESTROY
06-28 14:26:35.604: D/STOP(9225): false
06-28 14:26:35.604: D/TIMER(9225): / ONDESTROY

06-28 14:26:38.677: D/FORM(9225): ONCREATE
06-28 14:26:38.677: D/STOP(9225): false
06-28 14:26:38.687: D/FORM(9225): / ONCREATE
06-28 14:26:41.280: D/FORM(9225): ONDESTROY
06-28 14:26:41.280: D/STOP(9225): false
06-28 14:26:41.280: D/FORM(9225): / ONDESTROY

06-28 14:26:41.300: D/TIMER(9225): ONSTARTCOMMAND
06-28 14:26:41.300: D/TIMER(9225): / ONSTARTCOMMAND
06-28 14:26:41.300: D/TIMER(9225): ONDESTROY
06-28 14:26:41.300: D/STOP(9225): false
06-28 14:26:41.300: D/TIMER(9225): / ONDESTROY

06-28 14:26:44.353: D/FORM(9225): ONCREATE
06-28 14:26:44.353: D/STOP(9225): true
06-28 14:26:44.353: D/FORM(9225): / ONCREATE
06-28 14:26:46.345: D/FORM(9225): ONDESTROY
06-28 14:26:46.345: D/STOP(9225): true
06-28 14:26:46.355: D/FORM(9225): / ONDESTROY

06-28 14:26:46.365: D/TIMER(9225): ONSTARTCOMMAND
06-28 14:26:46.375: D/TIMER(9225): / ONSTARTCOMMAND
06-28 14:26:46.375: D/TIMER(9225): ONDESTROY
06-28 14:26:46.385: D/STOP(9225): true
06-28 14:26:46.385: D/TIMER(9225): / ONDESTROY
Sì... pare che quello che conta sia il valore all'inizio del metodo.
Quindi la soluzione più pratica che mi venga in mente è bloccare la comparsa del Form se la variabile è pari a true, perché al momento in cui è cessato il metodo TIMER ONDESTROY il valore della variabile globale true sarà finalmente palese.

Provo a trovare una soluzione...

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  if(Globals.Stop)finish();
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_form);
  Log.d("FORM","ONCREATE");
  Log.d("STOP",""+Globals.Stop);

.....

Questa sembra funzionare.
Ma gettiamo un occhio a come vengono terminate tutte le componenti...
06-28 14:43:13.188: D/TIMER(13654): ONDESTROY
06-28 14:43:13.188: D/STOP(13654): false
06-28 14:43:13.188: D/TIMER(13654): / ONDESTROY

06-28 14:43:16.231: D/FORM(13654): ONCREATE
06-28 14:43:16.231: D/STOP(13654): true
06-28 14:43:16.231: D/FORM(13654): / ONCREATE
06-28 14:43:16.281: D/FORM(13654): ONDESTROY
06-28 14:43:16.281: D/STOP(13654): true
06-28 14:43:16.281: D/FORM(13654): / ONDESTROY

06-28 14:43:16.281: D/TIMER(13654): ONSTARTCOMMAND
06-28 14:43:16.281: D/TIMER(13654): / ONSTARTCOMMAND
06-28 14:43:16.281: D/TIMER(13654): ONDESTROY
06-28 14:43:16.291: D/STOP(13654): true
06-28 14:43:16.291: D/TIMER(13654): / ONDESTROY
Ecco: viene chiamato FORM, questo viene cessato e alla sua onDestroy viene chiamato Timer, il quale vede disattivato AlarmManager e non può più richiamare FORM.
Si potrebbe evitare il richiamo a vuoto di TIMER semplicemente ponendo il suo richiamo da FORM ONDESTROY come subordinato al valore false di Globals.Stop.

 public void onDestroy(){
  Log.d("FORM","ONDESTROY");
  Log.d("STOP",""+Globals.Stop);
  if(Globals.Stop==false) startService(new Intent(this, Timer.class));
  Log.d("FORM","/ ONDESTROY");
  super.onDestroy();
 }
E seguiamo...
06-28 14:47:13.302: D/TIMER(16187): ONDESTROY
06-28 14:47:13.302: D/STOP(16187): false
06-28 14:47:13.302: D/TIMER(16187): / ONDESTROY

06-28 14:47:16.355: D/FORM(16187): ONCREATE
06-28 14:47:16.355: D/STOP(16187): true
06-28 14:47:16.355: D/FORM(16187): / ONCREATE
06-28 14:47:16.415: D/FORM(16187): ONDESTROY
06-28 14:47:16.415: D/STOP(16187): true
06-28 14:47:16.415: D/FORM(16187): / ONDESTROY
Come previsto!
Forse a questo punto si potrebbe pure evitare il blocco di AlarmManager: una volta che questo abbia chiamato Form, questo si distrugge, e dal suo ONDESTROY non viene richiamato TIMER.

Ma lasciamocelo, come mezzo di sicurezza in più!

Nessun commento:

Posta un commento