2012-03-27 11 views
7

Oculto una vista a través de setVisibility(View.INVISIBLE). Más tarde, cuando trato de mostrar la vista de nuevo en un método diferente a través de setVisibility(View.VISIBLE) consigo la siguiente excepciónAndroid - setVisibility resultados en java.util.ConcurrentModificationException

03-28 01:32:05.450: E/AndroidRuntime(20895): FATAL EXCEPTION: main 
03-28 01:32:05.450: E/AndroidRuntime(20895): java.util.ConcurrentModificationException 
03-28 01:32:05.450: E/AndroidRuntime(20895): at java.util.HashMap$HashIterator.nextEntry(HashMap.java:796) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at java.util.HashMap$KeyIterator.next(HashMap.java:823) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:946) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:948) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:948) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:948) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:948) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:948) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewRoot.handleDragEvent(ViewRoot.java:3027) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewRoot.handleMessage(ViewRoot.java:2185) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.os.Handler.dispatchMessage(Handler.java:99) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.os.Looper.loop(Looper.java:132) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.app.ActivityThread.main(ActivityThread.java:4028) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at java.lang.reflect.Method.invokeNative(Native Method) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at java.lang.reflect.Method.invoke(Method.java:491) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602) 
03-28 01:32:05.450: E/AndroidRuntime(20895): at dalvik.system.NativeStart.main(Native Method) 

Cuando comente la línea que cambia la visibilidad de nuevo a visible, no lo entiendo la excepción.

pensé por primera vez que la excepción podría ser causado por algún otro código iteración a través de un mapa hash, sin embargo, no hago ninguna modificación al iterar a través de los HashMaps que utilizo, ni tengo multihilo, lo que parece ser el razón más común para esta excepción. Además, no recibo la excepción cuando no cambio la visibilidad.

EDIT:
La excepción se produce en un fragmento personalizado. A continuación se muestra el código donde iterar sobre el hashmap (mWidgetConfig) que contiene información sobre la configuración de widgets personalizados que estoy tratando de restaurar. El hashmap es una variable pública en el fragmento.

En una OnDragListener que se crea por el fragmento, puedo actualizar el HashMap de acuerdo con una cierta operación de arrastre, así:

// Update the widget configuration of the fragment that created this listener 
       mFragment.mWidgetConfig.put(startCircleTag, "0"); 

También iterar sobre la HashMap para comprobar una cierta condición, pero I don' t realizar cualquier modificación durante la iteración:

Iterator<String> keySetItr = mFragment.mWidgetConfig.keySet().iterator(); 
     while(keySetItr.hasNext()) { 
      String tag = keySetItr.next(); 
      if(mFragment.mWidgetConfig.get(tag).equals((String) destSocket.getTag())) { 
       // do something, though no modification of the hashmap 
       break; 

      } 
     } 

Además i Realice una iteración en el fragmento de sí mismo mientras que intenta restaurar la configuración del widget. A continuación se muestra el código que utilizo para configurar el widget de acuerdo con el HashMap:

public void configureWidgets() { 
    resetWidgets(); 

    Iterator<String> keySetItr = mWidgetConfig.keySet().iterator(); 
    while(keySetItr.hasNext()) { 
     String tag = keySetItr.next(); 
     Integer value = Integer.parseInt(mWidgetConfig.get(tag)); 

     ImageView destSocket = null; 
     switch(value) { 
     case 0: 
      // The circle will not be connected to any socket 
      continue; 
     case 1: 
      destSocket = mSocket1; 
      break; 
     case 2: 
      destSocket = mSocket2; 
      break; 
     case 3: 
      destSocket = mSocket3; 
      break; 
     } 

     ImageView startCircle = (ImageView) mLayout.findViewWithTag(tag); 
     ImageView startPlug = (ImageView) mLayout.findViewWithTag(tag + "_plug"); 

     // Replace the drawable of destSocket 
     destSocket.setBackgroundDrawable(getActivity().getResources().getDrawable(R.drawable.socket_plugged)); 

     // Hide plug view 
     startPlug.setVisibility(View.INVISIBLE); 

     // Draw a line between the start circle view and the destination socket view 
     mConnectionLinesView.addLine(startCircle, destSocket); 
    } 
} 


public void resetWidgets() { 
    // Remove all lines 
    mConnectionLinesView.removeLines(); 

    // Show all eventually previously hidden plugs 
    //mPlug1.setVisibility(View.VISIBLE); 
    //mPlug2.setVisibility(View.VISIBLE); 
    //mPlug3.setVisibility(View.VISIBLE); 

    // Set to backround drawable of the socket to the initial one 
    mSocket1.setBackgroundDrawable(getActivity().getResources().getDrawable(R.drawable.socket).mutate()); 
    mSocket2.setBackgroundDrawable(getActivity().getResources().getDrawable(R.drawable.socket).mutate()); 
    mSocket3.setBackgroundDrawable(getActivity().getResources().getDrawable(R.drawable.socket).mutate()); 
} 

Tan pronto como las líneas que marcan la visibilidad de los "tapones" arriba se utilizan en el código, me sale la excepción.

SOLUCIÓN
La razón por la excepción echaron es que llamé a los métodos de configuración de la cuenta de DragEvent.ACTION_DRAG_ENDED caso de la OnDragListener. Cuando coloco el mismo código en la declaración de caso DragEvent.ACTION_DROP, la excepción no se lanza. No hay idea de por qué. Gracias por su ayuda chicos

+0

publica tu código para iterar hashmap ... y crea esta excepción –

+0

así que ¿cómo es que la excepción solo se produce cuando cambio la visibilidad? – Schnodahipfe

+0

son eliminar o agregar en 'while (iterator.hasNext())' –

Respuesta

0

Try usando:

setVisibility(View.GONE); 
setVisibility(View.VISIBLE); 
+0

Desafortunadamente eso no ayudó, todavía recibo la misma excepción – Schnodahipfe

+0

Esto parece no ser un problema con la parte setVisibility. Esta url puede darle alguna pista sobre este tema - http://www.javacodegeeks.com/2011/05/avoid-concurrentmodificationexception.html –

+0

Esa es la cuestión, estoy en un entorno de subproceso único y no lo hago hacer alguna modificación durante las iteraciones. Si Android enhebró automáticamente su aplicación de alguna manera, esta podría ser la respuesta – Schnodahipfe

14

Como entiendo que esto es causado por ViewGroup detalles de implementación. Y no está conectado con multihilo.

Cuando se inicia el arrastre ViewGroup crea un HashSet de vistas secundarias que se deben notificar sobre el evento ACTION_DRAG_ENDED. Este es un conjunto de niños visibles. Cuando se cambia la visibilidad del niño, un ViewGroup correspondiente modifica ese conjunto (agregando un niño si su visibilidad es VISIBLE). Y en tu caso ocurre durante iteraciones sobre esa colección.

Piense, la solución más fácil para usted es posponer el cambio de visibilidad.

view.post(new Runnable() { 
    public void run() { 
    view.setVisibility(View.VISIBLE); 
    } 
}); 

Y excepción no se produce cuando se pone el código en la declaración ACTION_DROP caso, ya que el conjunto no está siendo iterado en el momento que cambie la vista visibilidad.

Para obtener más información, consulte el código fuente ViewGroup.dispatchDragEvent(DragEvent).

+1

Gracias, muy útil –

0

Otra posible solución es envolver la vista que se puede arrastrar en algunos ViewGroup (por ejemplo, FrameLayout) y mantenerla visible todo el tiempo.

De esta manera, solo desaparecerá la vista que se puede arrastrar contenida, dejando un agujero donde estaba (igual que antes), pero el elemento primario del envoltorio no se notificará de que el elemento arrastrable esté oculto.

absoluto se refiere a ir de

ViewGroup:parent 
┗ View:draggable (toggling setVisible on this one, parent gets notified) 

a

ViewGroup:parent 
┗ ViewGroup:wrapper (setVisible never called on this one) 
    ┗ View:draggable (toggling setVisible on this one, wrapper gets notified) 

El ConcurrentModificationException se evita aquí porque la problemática Map sólo contiene un elemento, por lo tanto, se realiza una iteración, lo que significa una llamada a Iterator.hasNext/.next .

decidir por sí mismo si se trata de un truco :)

Nota: tu edición no tiene nada que ver con la cuestión, ya que la excepción se trata de ViewGroup.mDragNotifiedChildren y no su Map (ver StackTrace),

Cuestiones relacionadas