2012-03-27 8 views
7

Nascondo una vista tramite setVisibility(View.INVISIBLE). Più tardi, quando provo a mostrare la vista di nuovo in un metodo diverso tramite setVisibility(View.VISIBLE) ottengo la seguente eccezioneAndroid - setVisibilità risultati in 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) 

Quando io commento la linea che cambia la visibilità posteriore al visibile, non ottengo l'eccezione.

Innanzitutto ho pensato che l'eccezione sarebbe stata causata da qualche altro codice che iterava tramite una hashmap, tuttavia, non eseguo alcuna modifica mentre eseguo l'iterazione tramite le hashmap che uso, né ho il multithreading, che sembra essere il motivo più comune per questa eccezione. Inoltre non ottengo l'eccezione quando non cambio la visibilità.

EDIT:
L'eccezione si verifica in un frammento personalizzato. Di seguito è riportato il codice in cui viene eseguita l'iterazione su hashmap (mWidgetConfig) che contiene informazioni sulla configurazione di widget personalizzati che sto tentando di ripristinare. L'hashmap è una variabile pubblica nel frammento.

In OnDragListener che viene creato dal frammento, aggiorno il hashmap secondo un certo un'operazione di trascinamento, in questo modo:

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

Ho anche iterare il hashmap per verificare una certa condizione ma indosso' t fare qualsiasi modifica durante l'iterazione:

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; 

      } 
     } 

Inoltre i Effettuare un'iterazione nel frammento stessa durante il tentativo di ripristinare la configurazione del gadget. Di seguito è riportato il codice che uso per configurare il widget in base al 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()); 
} 

Non appena le linee che impostare la visibilità dei "tappi" di cui sopra vengono utilizzati nel codice, ottengo l'eccezione.

SOLUZIONE
Il motivo l'eccezione ottenuto gettato è che ho chiamato i metodi di configurazione nel caso DragEvent.ACTION_DRAG_ENDED dichiarazione del OnDragListener. Quando inserisco lo stesso codice nell'istruzione case DragEvent.ACTION_DROP, l'eccezione non viene generata. Nessun indizio perché. Grazie per il vostro aiuto ragazzi

+0

inserisci il tuo codice per iterare hashmap ... e crea questa eccezione –

+0

quindi come mai l'eccezione viene lanciata solo quando cambio la visiblity? – Schnodahipfe

+0

sono rimossi o aggiunti 'while (iterator.hasNext())' –

risposta

0

utilizzare:

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

Sfortunatamente non è stato d'aiuto, ho ancora la stessa eccezione – Schnodahipfe

+0

Questo sembra non essere un problema con parte setVisibility. Questo URL potrebbe darti qualche suggerimento su questo problema - http://www.javacodegeeks.com/2011/05/avoid-concurrentmodificationexception.html –

+0

Questo è il punto, sono in un ambiente a thread singolo e non lo faccio fare eventuali modifiche durante le iterazioni. Se Android ha eseguito il threading automatico della tua app in qualche modo, questa potrebbe essere la risposta – Schnodahipfe

14

quanto ho capito questo è causato da ViewGroup dettagli di implementazione. E non è collegato al multithreading.

All'avvio del trascinamento, ViewGroup crea un hashset di viste figlio che devono essere notificate sull'evento ACTION_DRAG_ENDED. Questo è un insieme di bambini visibili. Quando viene modificata la visibilità del bambino, un corrispondente ViewGroup modifica il set (aggiungendo un figlio se la sua visibilità è VISIBLE). E nel tuo caso succede durante le iterazioni su quella raccolta.

Pensa, la soluzione più semplice per te è posticipare il cambio di visibilità.

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

E eccezione non succede quando si mette il codice nel comunicato ACTION_DROP caso perché quel set non viene iterato in questo momento si modifica la visibilità vista.

Per dettagli, vedere il codice sorgente ViewGroup.dispatchDragEvent(DragEvent).

+1

Grazie, molto utile –

0

Un'altra soluzione possibile è avvolgere la vista trascinabile in alcuni ViewGroup (ad esempio FrameLayout) e tenerlo sempre visibile.

In questo modo solo la vista trascinabile contenuta all'interno scomparirà lasciando un buco dov'era (proprio come prima), ma il genitore del wrapper non verrà informato dell'elemento trascinabile nascosto.

esentially vanno da

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) 

Il ConcurrentModificationException viene evitato qui perché la problematica Map contiene un solo elemento, quindi un'iterazione è fatto, che significa che una chiamata a Iterator.hasNext/.next .

decidere da sé se questo è un hack :)

Nota: la modifica non ha nulla a che fare con la domanda, perché l'eccezione è di circa ViewGroup.mDragNotifiedChildren e non il tuo Map (vedi stacktrace),

Problemi correlati