Firebase的ConcurrentModificationException

时间:2018-06-25 07:16:28

标签: java android concurrentmodification

我一直从Firebase收到此ConcurrentModificationException

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 :(得分:1)

问题最像是将新内容添加到列表中。公用for(Type obj : list)循环使用Iterator接口提供的公用Iterable。但是,在迭代过程中修改列表会抛出ConcurrentModificationException

错误代码(引发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 ) );
  }
}

注意:这只是使用整数的示例,因为我无法访问OPs类型的对象。

答案 1 :(得分:0)

要在多线程环境中避免ConcurrentModificationException:

  1. 您可以将列表转换为数组,然后在数组上进行迭代。这种方法适用于中小型列表,但是如果列表很大,则会对性能产生很大影响。

  2. 您可以通过将列表放在同步块中来在锁定时锁定列表。不建议使用这种方法,因为它将停止多线程的好处。

  3. 如果使用的是JDK1.5或更高版本,则可以使用ConcurrentHashMap和CopyOnWriteArrayList类。这是推荐的方法。

要避免在单线程环境中发生ConcurrentModificationException:

您可以使用迭代器remove()函数从基础集合对象中删除该对象。但是在这种情况下,您可以从列表中删除同一对象,而不能删除任何其他对象。