2010-05-22 10 views
10

Tengo un botón con un OnClickListener. Para fines ilustrativos, considere un botón que muestra un cuadro de diálogo modal:Tratando de tocar rápidamente en los botones

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 el uso normal, aparece el cuadro de diálogo de alerta y bloquea más de entrada. Los usuarios deben cerrar el cuadro de diálogo antes de que puedan tocar nuevamente el botón.

Pero a veces se llama dos veces al OnClickListener del botón antes de que aparezca el cuadro de diálogo. Puede duplicar esto con bastante facilidad tocando muy rápido en el botón. En general, tengo que intentarlo varias veces antes de que suceda, pero tarde o temprano activaré varias llamadas onClick (...) antes de que el cuadro de diálogo bloquee la entrada.

Veo este comportamiento en Android 2.1 en el teléfono Motorola Droid. Hemos recibido 4 informes de fallas en el mercado, lo que indica que esto sucede ocasionalmente a las personas.

Dependiendo de lo que haga nuestro OnClickListeners, esto causa todo tipo de estragos. ¿Cómo podemos garantizar que los cuadros de diálogo de bloqueo realmente bloqueen la entrada después del primer toque?

+0

¿Intentó crear el AlertDialog fuera de OnClick() y simplemente llamó a show() dentro de onClick()? – jfpoilpret

Respuesta

17

Romain Guy confirmó que esto es de hecho un error en Android: "Sucede solo si el usuario logra presionar el botón dos veces en < 125ms. Creo que hemos solucionado ese posible error en Froyo".

Utilizaremos el patrón "panel de cristal" para evitar el error en sistemas operativos anteriores. Es decir, cubriremos la pantalla con una vista invisible. Después del primer clic, vamos a hacer que la vista sea "visible" para que intercepte los eventos táctiles subsiguientes.

No es suficiente para evitar más eventos con solo un botón. Debe bloquear todos los eventos posteriores para toda la actividad hasta que se cierre el diálogo, se reanude la actividad, etc., momento en el que volverá a hacer que el panel de cristal sea "invisible".

Si eso no funciona, tendremos que vivir con esto y tolerar mejor los eventos extra inesperados.

+0

Guau ... ¿eres * el * Bob Lee? –

+0

Supongo que eso depende de quién sea "el" Bob Lee. :-) No conozco ningún otro programador de Bob Lee. :-) –

+1

Bob y yo vamos con algo muy similar a lo que Bob describe arriba. La principal diferencia es que nuestro "panel de vidrio" no es una vista real. En cambio, todas nuestras actividades extienden una actividad base común, y todos nuestros diálogos amplían un diálogo base. Como tenemos estas clases base, podemos introducir un indicador booleano en cada una. Esta bandera indica si estamos aceptando o bloqueando la entrada. En cada una de estas clases base, reemplazamos dispatchTouchEvent. Basado en la bandera, simplemente podemos devolver verdadero, que intercepta y bloquea el evento. Este enfoque parece funcionar. –

9

Gracias por probar, mdma, pero este es un problema de plataforma, no es un problema con nuestro código. Lo que es peor, aparentemente no es un problema que pueda solucionarse en el código de usuario (requiere detalles del controlador de pantalla táctil que no se transfieren). Además, su ejemplo de código no hace lo que cree que hace. show() no muestra el diálogo inmediatamente. Agrega un mensaje al final de la cola de eventos que finalmente muestra el diálogo. Más eventos táctiles ya podrían estar en cola esperando para ejecutarse después de que onClick() regrese.

No estoy seguro de por qué las personas votan esa respuesta.

+0

Hola, he borrado mi respuesta. Pero no veo cómo no es posible determinar si se encuentra entre estados, entre manejar el clic y mostrar el diálogo, y luego ignorar más clics. – mdma

Cuestiones relacionadas