web-dev-qa-db-fra.com

removeCallbacks n'arrête pas runnable

J'appelle depuis une méthode:

myHandler.postDelayed(mMyRunnableHide, 6000);

qui appelle:

public Runnable mMyRunnableHide = new Runnable()
{

    public void run()
    {
        mTextDisplay.setText("");
        DisplayX();
    }
 };

si un bouton à l'écran est cliqué, je veux arrêter le runnable:

   Button next = (Button) findViewById(R.id.Breaction);
    next.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {

            myHandler.removeCallbacks(mMyRunnableHide);

            mTextDisplay.setText("");
            DisplayX();
            }
        });   
    }

le removecallbacks n'arrête pas le runnable. Qu'est-ce que je fais mal? Est-ce que j'utilise la bonne méthode? Je veux juste que le runnable "Non Run" quand l'utilisateur clique sur le bouton.

Merci pour toute aide.

35
codemanusa

Handler.removeCallback est synchrone et fonctionnera bien si:

  1. Vous appelez postDelayed toujours dans le thread principal.
  2. Vous appelez removeCallback toujours dans le thread principal
  3. Vous n'appelez plus postDelayed après avoir supprimé les rappels.

Donc, dans votre cas, removeCallbacks est appelé à partir d'un gestionnaire de boutons, qui s'exécute dans le thread principal. Mais vous n'avez pas indiqué dans votre code le point d'où vous appelez postDelayed. Si vous appelez cela depuis un fil d’arrière-plan, c’est là que réside votre problème.

Si vous êtes certain de n'appeler aucune de ces méthodes à partir de threads d'arrière-plan et que l'ordre des appels est correct, vous risquez de laisser des tâches non annulées en vie du fait de la recréation d'activités sur des modifications de configuration (rotation d'écran, etc.). Assurez-vous toujours d'appeler à nouveau removeCallbacks dans la méthode onDestroy pour éviter ce genre de problème. 

9
Mister Smith

Voici une autre façon d'accomplir ce que décrit mtmurdock. Cette classe permettra d’éditer les variables d’instance dans toutes les classes pour lesquelles votre Runnable est définie en tant que classe interne anonyme.

package support;

/**
* Runnable that can be stopped from executing
*/
public abstract class KillableRunnable implements Runnable{

private boolean isKilled=false;

/**
 * Instead of Overriding run(), override this method to perform a Runnable operation. 
 * This will allow editing instance variables in the class that this Runnable is defined
 */
public abstract void doWork();

//The handler that posts this Runnable will call this method. 
//By default, check if it has been killed. doWork() will now be the method 
//override to implement this Runnable
@Override
final public void run(){
    if(!isKilled){
        doWork();
    }
}

final public void kill(){
    isKilled=true;
}
}
6
James L.

Je ne pense pas que removeCallbacks (..) arrête uniquement les messages en attente (Runnables) , Je pense que removeCallbacks (..) ne fonctionne pas pour une autre raison, mais je ne le sais pas. parce que postDelayed (..) et removeCallbacks (..) sont dans le même fil

0
xiangyu shi