【发布时间】:2019-02-10 17:51:12
【问题描述】:
我得到 java.util.ConcurrentModificationException,我不知道为什么。
在 Logcat 中它指向此代码,但我没有看到任何可能导致 ConcurrentModificationException 的内容。
private void initRecyclerView() {
Main.musicList = Main.songs.songs;
Log.d(TAG, "Main.musicList: " + String.valueOf(Main.musicList));
if ((Main.musicList != null) && (!Main.musicList.isEmpty())) {
// Connects the song list to an adapter
// (Creates several Layouts from the song list)
allSongsAdapter = new AllSongsAdapter(getActivity(), Main.musicList);
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
recyclerViewSongs.setLayoutManager(linearLayoutManager);
recyclerViewSongs.setHasFixedSize(true);
recyclerViewSongs.setAdapter(allSongsAdapter);
}
}
Main.musicList 是一个公共静态 ArrayList musicList = null;在另一个班级。
而Main.songs.songs是一个公共的ArrayListsongs = null;在我的课堂上,我获取设备上的所有歌曲并用它们填充数组列表。
在 onDestroy 中我调用:
musicList = null;
编辑
好的,我发现了问题,当我不调用 onDestroy musicList = null 时,没有 ConcurrentModificationException。
但是我如何在 onDestroy 中取消引用一个数组列表,以便它可以被垃圾收集?
编辑
所以问题不在于 onDestroy 调用,当我打开应用程序并且我的数组列表中填充了所有歌曲时发生错误,然后我关闭应用程序并重新打开它,然后引发异常。
我如何填充歌曲数组
songs = new ArrayList<>();
// Columns retrieved from the system database (MediaStore.Audio.Media).
String[] projection1 = {
SONG_ID,
SONG_TITLE,
SONG_ARTIST,
SONG_ALBUMID,
SONG_ALBUM,
SONG_FILEPATH,
SONG_DURATION,
SONG_YEAR,
};
// Limits results to only show MUSIC files.
// It's a SQL "WHERE" clause - it becomes `WHERE IS_MUSIC NOT EQUALS ZERO`.
final String musicsOnly = SONG_IS_MUSIC + "!=0";
// Querying the Media DATABASE.
cursor = resolver.query(musicUri, projection1, musicsOnly, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
do {
// Creating a SONG from the VALUES in each column.
Song song = new Song(cursor.getLong(cursor.getColumnIndexOrThrow(SONG_ID)),
cursor.getString(cursor.getColumnIndexOrThrow(SONG_FILEPATH)));
song.setTitle(cursor.getString(cursor.getColumnIndexOrThrow(SONG_TITLE)));
song.setArtist(cursor.getString(cursor.getColumnIndexOrThrow(SONG_ARTIST)));
song.setAlbumID(cursor.getLong(cursor.getColumnIndexOrThrow(SONG_ALBUMID)));
song.setAlbum(cursor.getString(cursor.getColumnIndexOrThrow(SONG_ALBUM)));
song.setDuration(cursor.getLong(cursor.getColumnIndexOrThrow(SONG_DURATION)));
song.setYear(cursor.getInt(cursor.getColumnIndexOrThrow(SONG_YEAR)));
// Using the previously created maps to add the current song GENRE.
String currentGenreID = songIdToGenreIdMap.get(Long.toString(song.getId()));
String currentGenreName = genreIdToGenreNameMap.get(currentGenreID);
song.setGenre(currentGenreName);
// Adding the Song to the global array list 'songs'.
songs.add(song);
} while (cursor.moveToNext());
}
}catch (Exception e){
// Exception caught because no songs were found.
Log.e(TAG, "Exception caught because no songs were found!", e);
throw new Exception();
}finally {
if (cursor != null ){
cursor.close();
}
}
【问题讨论】:
-
我相信只要对对象的引用不存在,它就会自动用于垃圾收集。 Java GC 实际上很聪明,可以选择这样的对象。即使您可以调用垃圾收集器方法,也不能保证 Nulling 是一回事,但会出现另一个问题。
-
您介意发布初始化歌曲数组的其他类吗?一般来说,你应该尽量避免这样的静态引用,它们很容易导致内存泄漏,不是一个好的做法。
-
@Niko 添加了课程
-
@Niko 所以我应该摆脱静态数组列表 Main.musicList?
-
我认为这不能解决问题。正如我在之前的评论中提到的,当读取和修改同时发生时,会发生此错误。这类问题很难调试和重现。只需检查您正在修改列表的每个地方,并检查在您修改时是否有可能发生读取。
标签: java android concurrentmodification