2010-05-22 5 views
10

J'ai un bouton avec un OnClickListener. À titre d'exemple, envisager un bouton qui affiche une boîte de dialogue modale:Traitement des touches rapides sur les boutons

public class SomeActivity ... { 

    protected void onCreate(Bundle state) { 
    super.onCreate(state); 

    findViewById(R.id.ok_button).setOnClickListener(
     new View.OnClickListener() { 
     public void onClick(View v) { 
      // This should block input 
      new AlertDialog.Builder(SomeActivity.this) 
      .setCancelable(true) 
      .show(); 
     } 
    }); 
} 

En utilisation normale, la boîte de dialogue d'alerte apparaît et les blocs d'entrée plus loin. Les utilisateurs doivent fermer la boîte de dialogue avant de pouvoir appuyer à nouveau sur le bouton.

Mais parfois, le OnClickListener du bouton est appelé deux fois avant que la boîte de dialogue ne s'affiche. Vous pouvez reproduire cela assez facilement en tapant très vite sur le bouton. Je dois généralement essayer plusieurs fois avant que cela ne se produise, mais tôt ou tard je déclencherai plusieurs appels onClick (...) avant que la boîte de dialogue bloque l'entrée.

Je vois ce comportement dans Android 2.1 sur le téléphone Motorola Droid. Nous avons reçu 4 rapports d'accident dans le Market, indiquant que cela arrive parfois aux gens. En fonction de ce que font nos OnClickListeners, cela provoque toutes sortes de dégâts. En fonction de ce que font nos OnClickListeners. Comment pouvons-nous garantir que les boîtes de dialogue de blocage bloquent réellement l'entrée après le premier tapotement?

+0

Avez-vous essayé de créer le AlertDialog en dehors de onClick() et appelez simplement show() dans onClick()? – jfpoilpret

Répondre

17

Romain Guy a confirmé qu'il s'agit bien d'un bug dans Android: "Cela n'arrive que si l'utilisateur parvient à appuyer deux fois sur le bouton en < 125ms. Je crois que nous avons corrigé cette erreur possible dans Froyo."

Nous allons utiliser le modèle de "panneau de verre" pour contourner le bogue sur les anciens systèmes d'exploitation. Autrement dit, nous allons couvrir l'écran avec une vue invisible. Après le premier clic, nous rendrons la vue "visible" pour intercepter les événements tactiles ultérieurs.

Il ne suffit pas d'empêcher d'autres événements sur un seul bouton. Vous devez bloquer tous les événements suivants pour l'ensemble de l'activité jusqu'à ce que la boîte de dialogue soit fermée, que l'activité soit reprise, etc., auquel cas vous redéfinissez le volet de verre.

Si cela ne fonctionne pas, nous devrons simplement vivre avec cela et mieux tolérer des événements supplémentaires inattendus.

+0

Wow ... êtes-vous * le * Bob Lee? –

+0

Je suppose que cela dépend de qui "le" Bob Lee est. :-) Je ne connais pas d'autres programmeurs de Bob Lee. :-) –

+1

Bob et moi partons avec quelque chose de très similaire à ce que Bob décrit plus haut. La principale différence est notre "vitre" n'est pas une vue réelle. Au lieu de cela, toutes nos activités étendent une activité de base commune et toutes nos boîtes de dialogue étendent une boîte de dialogue de base. Puisque nous avons ces classes de base, nous sommes capables d'introduire un drapeau booléen dans chacune d'entre elles. Ce drapeau indique si nous acceptons ou bloquons les entrées. Dans chacune de ces classes de base, nous surchargeons dispatchTouchEvent. Basé sur le drapeau, nous pouvons simplement renvoyer vrai, qui intercepte et bloque l'événement. Cette approche semble fonctionner. –

9

Merci d'avoir essayé, mdma, mais c'est un problème de plate-forme, pas un problème avec notre code. Pire encore, ce n'est apparemment pas un problème que l'on peut contourner dans le code de l'utilisateur (cela nécessite des détails du pilote de l'écran tactile qui ne sont pas transmis). En outre, votre exemple de code ne fait pas ce que vous pensez qu'il fait. show() n'affiche pas le dialogue immédiatement. Il ajoute un message à la fin de la file d'attente des événements qui affiche éventuellement la boîte de dialogue. D'autres événements tactiles peuvent déjà être dans la file d'attente en attente d'exécution après le retour de onClick().

Je ne sais pas pourquoi les gens votent pour cette réponse.

+0

Bonjour, j'ai supprimé ma réponse. Mais je ne vois pas comment il n'est pas possible de déterminer si vous êtes entre deux états - entre la gestion du clic et l'affichage de la boîte de dialogue, puis l'ignorance des clics supplémentaires. – mdma

Questions connexes