2012-03-27 62 views
7

我通過setVisibility(View.INVISIBLE)隱藏視圖。後來,當我試圖表明的觀點再次在不同的方法,通過setVisibility(View.VISIBLE)我得到下面的異常Android - setVisibility結果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) 

當我註釋掉改變能見度回到可見行了,我不明白的例外。

我首先想到的是,其他代碼會通過hashmap迭代引發異常,但是,在迭代我使用的hashmaps時,我沒有做任何修改,我也沒有多線程,這似乎是這種例外的最常見原因。當我不改變能見度時,我也不例外。

編輯
自定義片段中發生異常。下面是迭代散列圖(mWidgetConfig)的代碼,其中包含有關我嘗試還原的自定義窗口小部件配置的信息。散列映射是片段中的公共變量。

在由所述片段創建的OnDragListener,我按一定的拖動操作更新的散列映射,如下:

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

我還遍歷散列映射,以檢查特定的條件,但我不在迭代過程中做任何修改:

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; 

      } 
     } 

另外,我在片段本身做了一次迭代,同時嘗試恢復窗口小部件的配置。下面是我用根據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()); 
} 

只要是上面設置在代碼中使用的「插頭」的知名度線,我得到的異常。

SOLUTION
究其原因,除了得到拋出的是我叫的OnDragListenerDragEvent.ACTION_DRAG_ENDED case語句的配置方法。當我將相同的代碼放入DragEvent.ACTION_DROP case語句時,該異常不會被拋出。不知道爲什麼。感謝您的幫助球員

+0

發佈迭代hashmap的代碼...並創建這個異常 – 2012-03-28 10:29:51

+0

,那麼當我更改可見性時,怎麼纔會拋出異常呢? – Schnodahipfe 2012-03-28 14:51:35

+0

正在刪除或添加'while(iterator.hasNext())' – 2012-03-28 14:55:04

回答

0

嘗試使用:

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

不幸的是,沒有幫助,我仍然得到相同的異常 – Schnodahipfe 2012-03-28 12:51:07

+0

這似乎不是一個問題與setVisibility部分。 這個網址可能會給你一些關於這個問題的提示 - http://www.javacodegeeks.com/2011/05/avoid-concurrentmodificationexception.html – 2012-03-28 14:51:48

+0

就是這樣,我在單線程環境中,而且我不在迭代期間做任何修改。如果Android以某種方式自動穿線您的應用程序,這可能是答案 – Schnodahipfe 2012-03-28 15:11:57

14

據我所知,這是通過ViewGroup實現細節造成的。並沒有與多線程連接。

當開始拖動時ViewGroup創建一個子視圖的HashSet,必須通知有關ACTION_DRAG_ENDED事件的HashSet。這是一組可見的孩子。當兒童可見度發生變化時,對應的ViewGroup會修改該設置(如果其可見性爲VISIBLE,則添加子項)。在你的情況下,它會在對該集合的迭代中發生。

想一想,最簡單的解決方案是推遲可見性更改。

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

和異常,當你把你的代碼放到ACTION_DROP case語句,因爲該組不被此刻的重複更改視圖可視性不會發生。

詳情請參閱ViewGroup.dispatchDragEvent(DragEvent)源代碼。

+1

謝謝,非常有用 – 2012-07-28 13:21:03

0

另一種可能的解決方案是將可拖動的視圖放在一些ViewGroup(例如FrameLayout)中,並始終保持可見。

這樣,只有包含在其中的可拖動視圖纔會消失,並留下一個空洞(與以前一樣),但是包裝器的父級將不會收到被隱藏的可拖動的通知。

Esentially去從

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

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

ConcurrentModificationException這裏避免因爲問題Map只包含一個元素,因此一個迭代完成,這意味着一個呼叫Iterator.hasNext/.next

自己決定,如果這是一個黑客:)

注:您的修改已無關的問題,因爲異常是關於ViewGroup.mDragNotifiedChildren而不是你的Map(見堆棧跟蹤),

相關問題