Abnormal behavior of a runnable when leaving an activity and restarting it

1

It turns out that in a Activity I am using a grid of images fed by a Adapter , which is refreshed thanks to a Runnable that I run every certain time, and it is always the same (ex: 500 milliseconds) and I do not change it anywhere in the code.

I have overwritten the onBackPressed method, because I need to save at the end of the activity and I close the Activity with a finish() and start the previous activity from which I started.

The problem I have is that if I start the same activity again, the timer stops behaving properly and instead of running every X milliseconds that I indicate, it is executed when it suits you, which is generally less than X milliseconds and it's not a constant amount. So my grid does not adequately refresh the images.

Has something similar happened to someone?

The activity that contains the grid I have implemented it like this ...

    public class PantallaTragaperrasBotonera extends FragmentActivity {
        private Tragaperras juegoTragaperras;
        private GridView gridview;
        private ImageAdapter imageadapter;              
        public byte estado;

        //se le pasa como parámetro al INTENT
        private int numEjecuciones;

        //los tres primeros y el Ya normal para el resto.

        private Runnable swapImages = new Runnable(){
            public void run(){
                Log.d("DEBUGUEANDO", "PantallaTragaperrasBotonera: INICIO private Runnable swapImages = new Runnable(){ public void run(){);");

                //Si no se han pulsado los tres botones         
                if (!juegoTragaperras.finalizado() && !contador.tiempoFinalizado()){
                        Log.d("DEBUGEANDO","if (!juegoTragaperras.finalizado() && !contador.tiempoFinalizado()){");
                        mostrarImagenes(this);                      
                        juegoTragaperras.incrementarPosicionesMomentosParo();

                }else{
                    Log.d("DEBUGUEANDO","PantallaTragaperrasBotonera: }else{");
                    //Se muestra el cuadro de diálogo con la puntuación obtenida
                    if (estado == 0){

                        estado = 1;
                        gridview.postDelayed(swapImages, 0);

                    //Se muestra el grid con las animaciones pertinentes y la animación del contador
                    }else if (estado ==1){
                        gridview.postDelayed(swapImages,0);
                    }else if (estado == 2){                     
                        imageadapter.notifyDataSetChanged();                            
                        gridview.setAdapter(imageadapter);
                        gridview.invalidateViews();
                        gridview.postDelayed(swapImages, (Tragaperras.ganado() ? 5000:1000));                       
                        estado = 3;
                    //finalmente se finaliza la actividad
                    }else if (estado == 3){                     
                        try{

                            Intent i = new Intent(PantallaTragaperrasBotonera.this, PantallaObjetivo.class);
                            i.putExtra("com.example.HappyBoom.PUNTOS_CONTADOR", contador.obtenerPuntuacionContador());
                            PantallaTragaperrasBotonera.this.startActivity(i);

                            finish();
                            Runtime.getRuntime().gc();
                        }catch(Exception e){}               
                    }               
                }               
            }

        };

        //para manejar el evento OnTimerListener    
        @Override
        protected void onCreate(Bundle savedInstanceState) {        

            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);          
            setContentView(R.layout.activity_tragaperrasbotonera);

            //Obtenemos las variables entre actividades         
            Bundle extra = this.getIntent().getExtras();
            puntosContador = extra.getLong("com.example.HappyBoom.PUNTOS_CONTADOR");
            numEjecuciones = extra.getInt("com.example.HappyBoom.NUMERO_EJECUCIONES");
            numEjecuciones = 1;

            juegoTragaperras = Tragaperras.getInstance();
            juegoTragaperras.reiniciarInstancia();

            gridview = (GridView) findViewById(R.id.gvTragaperras);         
            gridview.setNumColumns(juegoTragaperras.getNumeroColumnas());
            imageadapter = new ImageAdapter(this, ImageAdapter.TipoJuego.TRAGAPERRAS);
            gridview.setAdapter(imageadapter);                              
            gridview.postDelayed(swapImages, 0);
            //...
        }

        @Override
        public void onBackPressed() {           
            guardarDatos();
            Intent i = new Intent(this, SeleccionaJuegos.class);
            if (i != null)this.startActivity(i);
            finish();
            Runtime.getRuntime().gc();      
        }

        private void guardarDatos(){
            //guarda los datos
        }       

        /**
         * Muestra las imágenes dependiendo del array de estados que el juego haya alcanzado.
         * @param runnable
         */     
        private void mostrarImagenes(Runnable runnable){
            imageadapter.notifyDataSetChanged();                
            gridview.setAdapter(imageadapter);
            gridview.invalidateViews();
            gridview.postDelayed(swapImages, Tragaperras.intervaloMuestraImagen);       
        }
}
    
asked by Lirulis 17.03.2016 в 10:30
source

4 answers

1

The problem you are having is that when doing the onBackPressed () you are not stopping the thread that you are running, therefore when you start the activity again, the thread starts again, that is why it takes less time to refresh the images. I recommend using the interface ScheduledExecutorService and Future , here's an example: p>

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Future<?> future = scheduler.scheduleAtFixedRate(runnable, INITIAL_DELAY, INTERVAL, TimeUnit.SECONDS)

In your case it would look like this:

Future<?> future = scheduler.scheduleAtFixedRate(swapImages, 0, 5, TimeUnit.SECONDS)

Finally to cancel it you have to use the property future.cancel () that I recommend using in the life cycles instead of the onBackPressed ():

@Override
public void onDestroy() {
    super.onDestroy();
    if (future != null && !future.isCancelled()) future.cancel(true);
}

This is all, I hope it helps you. Greetings.

    
answered by 18.03.2016 в 16:19
1

Thank you all for your contributions, but I have already solved it. It would simply be to add the following line in the onBackPressed method:

gridview.removeCallbacks(swapImages); 
    
answered by 19.03.2016 в 02:54
0

Try to do it using a Handler:

handler.postDelayed(new Thread(new Runnable(){
                        public void run(){
                            //Aqui el contenido del hilo
                        }
                    }).start(), 500);

Basically, what it does is run a thread after a time, in this case 500 ms and execute the block of code where there is the comment, in your case update the view.

Keep in mind that you can not change things in the view from threads that are outside the activity. You must contrive to do it or use an event bus. There's a lot of info on that in google.

Good luck!

    
answered by 17.03.2016 в 11:55
0
  

I run every so often, and it's always the same (ex: 500   milliseconds) and I do not change it anywhere in the code.

I can tell you that in reality if the time varies and depends on the state of the variable Tragaperras.ganado() :

        }else if (estado == 2){
            imageadapter.notifyDataSetChanged();
            gridview.setAdapter(imageadapter);
            gridview.invalidateViews();
            gridview.postDelayed(swapImages, (Tragaperras.ganado() ? 5000:1000));
            estado = 3;

If Tragaperras.ganado() is true there will be a delay of 5 seconds (5000ms), if Tragaperras.ganado() is false there will be a delay of 1 second (1000ms)

If you do not want to change the time you must have a fixed value, for example if you want to be late 1 second always:

 gridview.postDelayed(swapImages, (1000));
    
answered by 17.03.2016 в 22:27