Android - setVisibility приводит к появлению java.util.ConcurrentModificationException - PullRequest
8 голосов
/ 28 марта 2012

Я скрываю вид через setVisibility(View.INVISIBLE).Позже, когда я пытаюсь снова показать представление другим методом с помощью setVisibility(View.VISIBLE), я получаю следующее исключение

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)

Когда я закомментирую строку, которая изменяет видимость обратно на видимую, я неполучить исключение.

Сначала я подумал, что исключение будет вызвано тем, что какой-то другой код выполняет итерации по хеш-карте, однако я не делаю никаких изменений во время итерации по используемым хеш-таблицам, как и многопоточность.что, кажется, самая распространенная причина этого исключения.Также я не получаю исключение, когда не изменяю обратно видимость.

EDIT :
Исключение возникает в пользовательском фрагменте.Ниже приведен код, в котором я перебираю хэш-карту (mWidgetConfig), которая содержит информацию о конфигурации пользовательских виджетов, которые я пытаюсь восстановить.Хеш-карта является открытой переменной во фрагменте.

В OnDragListener, который создается фрагментом, я обновляю хеш-карту в соответствии с определенной операцией перетаскивания, например:

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

Я также перебираю hashmap, чтобы проверить определенное условие, но я не делаю никаких изменений во время итерации:

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;

            }
        }

Кроме того, я делаю одну итерацию в самом фрагменте, пытаясь восстановить конфигурацию виджета.,Ниже приведен код, который я использую для настройки виджета в соответствии с хэш-картой:

    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());
}

Как только в коде используются строки, которые задают видимость «плагинов», я получаю исключение.

РЕШЕНИЕ
Причина, по которой возникло исключение, заключается в том, что я вызвал методы конфигурации в DragEvent.ACTION_DRAG_ENDED операторе case OnDragListener.Когда я помещаю тот же код в оператор case DragEvent.ACTION_DROP, исключение не выдается.Понятия не имею, почему.Спасибо за вашу помощь, ребята

Ответы [ 3 ]

16 голосов
/ 26 июля 2012

Как я понимаю, это вызвано ViewGroup деталями реализации.И это не связано с многопоточностью.

Когда начинается перетаскивание, ViewGroup создает HashSet дочерних представлений, которые должны быть уведомлены о событии ACTION_DRAG_ENDED.Это набор видимых детей.Когда видимость дочернего элемента изменяется, соответствующий ViewGroup изменяет этот набор (добавляя дочерний элемент, если его видимость равна VISIBLE).И в вашем случае это происходит во время итераций этой коллекции.

Подумайте, самое простое решение для вас - отложить изменение видимости.

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

Исключение не возникает, когда вы помещаете свой код в оператор выражения ACTION_DROP, поскольку этот набор не повторяется в момент изменения видимости представления.

Подробнеесм. ViewGroup.dispatchDragEvent (DragEvent) исходный код.

0 голосов
/ 13 сентября 2014

Другое возможное решение состоит в том, чтобы обернуть ваше перетаскиваемое изображение в ViewGroup (например, FrameLayout) и сохранять его видимым все время.

Таким образом, только перетаскиваемый вид, содержащийся внутри, исчезнет, ​​оставив дыру в том месте, где он был (как и раньше), но родительская оболочка не получит уведомление о скрываемости перетаскиваемого объекта.

По сути идут от

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 (см. Stacktrace),

0 голосов
/ 28 марта 2012

Попробуйте использовать:

setVisibility(View.GONE);
setVisibility(View.VISIBLE);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...