ConcurrentModificationException от Firebase - PullRequest
0 голосов
/ 25 июня 2018

Я получаю это исключение ConcurrentModificationException от Firebase

Exception java.util.ConcurrentModificationException:
java.util.ArrayList$ArrayListIterator.next (ArrayList.java:573)

У меня заканчиваются идеи, как это исправить. Я уже пробовал так много изменений в коде. Исключение происходит в этой строке, согласно Firebase:

for (Show show : entityListLanguages) { }

Я уже несколько раз менял код (например, использовал «addAll» вне цикла и т. Д.), Но все равно получаю ошибку. Теперь у меня нет идей, что я мог бы изменить, чтобы это исправить.

Вот мой текущий код:

List<Show> entityListLanguages = movieTheatreShowtimesListItemRecyclerViewAdapter.getShowList(); // This just returns a list, no special thread of background process

movieLanguageList = new ArrayList<>();                               
availableLanguages.clear();                                          
for (Show show : entityListLanguages) {                              
    MovieLanguage movieLanguage = new MovieLanguage();               
    movieLanguage.setId(show.getSpokenLanguage());                   
    movieLanguage.setName(show.getSpokenLanguageFormatted());        
    if (!movieLanguageList.contains(movieLanguage)) {                
        movieLanguage.setMovieCount(1);                              
        movieLanguageList.add(movieLanguage);                        
    }                                                                
}                                                                    
availableLanguages.addAll(movieLanguageList);                        

Единственная строка, которую я могу себе представить, это может вызвать проблемы:

movieLanguageList.add(movieLanguage);      

но опять же я не знаю, как еще я мог бы решить это.

Я что-то упустил? Спасибо за любые подсказки.

Полная трассировка стека:

java.util.ArrayList$ArrayListIterator.next (ArrayList.java:573)
ch.cineman.ShowtimesFragmentHelper.updateAvailableLanguages (ShowtimesFragmentHelper.java:381)
ch.cineman.ShowtimesFragmentHelper.updateAvailableGenres (ShowtimesFragmentHelper.java:370)
ch.cineman.ShowtimesByMovieFragment$6$1.onListViewUpdated (ShowtimesByMovieFragment.java:301)
ch.cineman.MovieTheatreShowtimesListItemRecyclerViewAdapter$4$3.run (MovieTheatreShowtimesListItemRecyclerViewAdapter.java:569)
android.os.Handler.handleCallback (Handler.java:739)
android.os.Handler.dispatchMessage (Handler.java:95)
android.os.Looper.loop (Looper.java:158)
android.app.ActivityThread.main (ActivityThread.java:7224)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1230)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1120)

И более расширенный фрагмент кода:

Примечание: entityListLanguages ​​и entityListGenres не изменяются где-либо еще в коде.

private List<Show> entityListGenres;
private List<Show> entityListLanguages;
protected MovieTheatreShowtimesListItemRecyclerViewAdapter movieTheatreShowtimesListItemRecyclerViewAdapter;


    /**
     * Helper method
     */
    protected void updateAvailableGenres() {
        entityListGenres = movieTheatreShowtimesListItemRecyclerViewAdapter.getShowList();

        listedMovies = new ArrayList<>();
        movieGenreList = new ArrayList<>();
        availableGenres.clear();

        for (Show show : entityListGenres) {
            Movie movieX = show.getMovie();
            if (movieX != null) {
                if (!listedMovies.contains(movieX)) {
                    listedMovies.add(movieX);
                }
            }
        }

        for (Movie listedMovie : listedMovies) {
            if (listedMovie.getGenres() != null && listedMovie.getGenres().size() > 0) {
                for (MovieGenre movieGenre : listedMovie.getGenres()) {
                    if (!movieGenreList.contains(movieGenre)) {
                        movieGenre.setMovieCount(1);
                        movieGenreList.add(movieGenre);
                    }
                }
            }
        }

        availableGenres.addAll(movieGenreList);
        CinemanApplication.getCurrentAppInstance().setAvailableGenres(availableGenres);

        updateAvailableLanguages();
    }

    /**
     * Helper method
     */
    protected void updateAvailableLanguages() {
        entityListLanguages = movieTheatreShowtimesListItemRecyclerViewAdapter.getShowList();

        movieLanguageList = new ArrayList<>();
        availableLanguages.clear();
        for (Show show : entityListLanguages) {
            MovieLanguage movieLanguage = new MovieLanguage();
            movieLanguage.setId(show.getSpokenLanguage());
            movieLanguage.setName(show.getSpokenLanguageFormatted());
            if (!movieLanguageList.contains(movieLanguage)) {
                movieLanguage.setMovieCount(1);
                movieLanguageList.add(movieLanguage);
            }
        }
        availableLanguages.addAll(movieLanguageList);
        CinemanApplication.getCurrentAppInstance().setAvailableLanguages(availableLanguages);
    }

getShowList () находится в классе "movieTheatreShowtimesListItemRecyclerViewAdapter" и выглядит следующим образом:

List<Show> getShowList() {
    return showList;
}

Ответы [ 2 ]

0 голосов
/ 25 июня 2018

Больше всего проблема заключается в добавлении нового контента в список.Общий цикл for(Type obj : list) использует общий Iterator, предоставляемый интерфейсом Iterable.Однако, изменяя список во время итерации, выдает ConcurrentModificationException.

Неисправный код (Throws ConcurrentModificationException):

List<Integer> li = new Random().ints(10000,0,10).boxed().collect( Collectors.toList() );

for(Integer i : li)
{
  if(i.intValue() == 5)
  {
    li.add( Integer.valueOf( 2 ) );
  }
}

Чтобы предотвратить это, выможно использовать ListIterator, который обеспечивается интерфейсом List.

Рабочий код:

List<Integer> li = new Random().ints(10000,0,10).boxed().collect( Collectors.toList() );

for(ListIterator<Integer> it = li.listIterator();it.hasNext();)
{
  if(it.next().intValue() == 5)
  {
    it.add( Integer.valueOf( 2 ) );
  }
}

Примечание. Это только примериспользуя целые числа, так как у меня нет доступа к объектам типа OP.

0 голосов
/ 25 июня 2018

Чтобы избежать исключения ConcurrentModificationException в многопоточной среде:

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

  2. Вы можете заблокировать список во время итерации, поместив его в синхронизированный блок. Этот подход не рекомендуется, потому что он прекратит преимущества многопоточности.

  3. Если вы используете JDK1.5 или выше, вы можете использовать классы ConcurrentHashMap и CopyOnWriteArrayList. Это рекомендуемый подход.

Избежать исключения ConcurrentModificationException в однопоточной среде:

Вы можете использовать функцию итератора remove () для удаления объекта из базового объекта коллекции. Но в этом случае вы можете удалить тот же объект, а не любой другой объект из списка.

...