当前位置: 首页 > 知识库问答 >
问题:

JavaFX ObservableList-添加项导致ConcurrentModificationException

慕容星晖
2023-03-14

我有一个相册表,用户可以过滤和排序。

这是那张桌子的样子。如您所见,列是可排序的,顶部有一个文本框,当前正在筛选其中包含字符串“CU”的相册:

在专辑列表填充后,一切工作都很完美。

public class Library {
    final static ObservableList <Album> albums = FXCollections.observableArrayList( new ArrayList <Album>() );
    final static FilteredList <Album> albumsFiltered = new FilteredList <Album>( albums, p -> true );
    final static SortedList <Album> albumsSorted = new SortedList <Album>( albumsFiltered );
}
public void setupAlbumTable () {
    TableColumn artistColumn = new TableColumn( "Artist" );
    TableColumn yearColumn = new TableColumn( "Year" );
    TableColumn albumColumn = new TableColumn( "Album" );

    artistColumn.setCellValueFactory( new PropertyValueFactory <Album, String>( "albumArtist" ) );
    yearColumn.setCellValueFactory( new PropertyValueFactory <Album, Integer>( "year" ) );
    albumColumn.setCellValueFactory( new PropertyValueFactory <Album, String>( "title" ) );

    albumTable = new TableView();
    albumTable.getColumns().addAll( artistColumn, yearColumn, albumColumn );
    albumTable.setItems( Library.albumsSorted );

    Library.albumsSorted.comparatorProperty().bind( albumTable.comparatorProperty() );

    albumTable.getSortOrder().add( artistColumn );
    albumTable.getSortOrder().add( yearColumn );
    albumTable.getSortOrder().add( albumColumn );
}

设置FilterBox和谓词

public void setupAlbumFilterPane () {
    TextField filterBox = new TextField();
    filterBox.textProperty().addListener( ( observable, oldValue, newValue ) -> {
        Library.albumsFiltered.setPredicate( album -> {
            if ( newValue == null || newValue.isEmpty() ) {
                return true;
            }

            String[] filterTokens = newValue.toLowerCase().split( "\\s+" );

            ArrayList <String> albumMatchText = new ArrayList <String>();

            albumMatchText.add( album.getAlbumArtist().toLowerCase() );
            albumMatchText.add( album.getTitle().toLowerCase() );
            albumMatchText.add( album.getYear().toLowerCase() );

            for ( String filterToken : filterTokens ) {
                boolean fitlerTokenHasMatch = false;
                for ( String albumInfoString : albumMatchText ) {
                    if ( albumInfoString.contains( filterToken ) ) {
                        fitlerTokenHasMatch = true;
                    }
                }

                if ( !fitlerTokenHasMatch ) {
                    return false;
                }
            }

            return true;
        });
    });
}

添加数据或从列表中删除数据:这些函数保证只能从一个线程调用(不同于JavaFX),并且对ObservableListAlbums的所有修改只能由这个库线程进行。

public class Library {
    ...
    private static void addAlbum ( Album album ) {
        albums.add ( album );
    }

    private static void removeAlbum ( Album album ) {
        albums.remove ( album );
    }
    ...
}

最后,我尝试了两种不同的方法来解决这个问题:

public class Library {
    ...
    private static void addAlbum ( Album album ) {
        Platform.runLater( new Runnable() {
            public void run() {
                albums.add ( album );
            }
        });
    }

    private static void removeAlbum ( Album album ) {
        Platform.runLater( new Runnable() {
            public void run() {
                albums.remove ( album );
            }
        });
    }
    ...
}

以下是解决方案的关键特性:

  • tableview在任何时候都是可排序的
  • tableview在任何时候都是可过滤的
  • tableview会随着专辑列表的变化而定期更新(它不必是瞬时的,但至少每隔几秒钟更新一次)。

共有1个答案

满俊楠
2023-03-14

听起来像是你在一个项目接一个项目地添加。只是一次添加所有的项目不是一个选择?

 类似资料:
  • 这将导致以下生成错误: TaskExecutionException:任务“:App:TransformResourcesWithMergeJavaResforDebug”执行失败。在org.gradle.api.internal.tasks.execution.executeActionStaskExecuter.java:103),在org.gradle.api.internal.tasks.

  • 我有一个以编程方式定义的UISegmentedControl。 我正在尝试添加一个布局约束,以便在我的iPad旋转时,分段控件在旋转视图中的大小正确,而不是溢出屏幕。 我应用以下约束: 我的UIsegmentControl定义如下: 我没有出错,但是在运行时,我的分段控件消失了。不确定我在这里错过了什么,因为我过去只在故事板中做过自动布局。 我只想能够调整分段控件的宽度,所以我假设我只需要一个布局

  • 我有一个POJO类,用于使用Jackson进行反序列化。这个类包含所有类变量的默认构造函数、getter和setter方法<因为我需要一些关于POJO内容的高级逻辑,所以我添加了一个方法 但现在,我的单元测试在反序列化过程中失败,只有以下例外: 在我看来,Jackson似乎识别了一个get方法,并由此推断出,反序列化必须有一个类似的JSON属性 当我用@JsonIgnore注释方法时,测试成功了。

  • 我试图创建一组int数组,问题是,如果我尝试这样做: 那么s有两个对象,但应该只有一个。注意:它是否是HashSet并不重要 现在如果我试着用ArrayList做这个 那么s有一个对象。 我想了一种方法来避免第一个代码中的错误,并将每个数组的hashcode存储在hashset中,如下所示: 它适用于第一种情况(1,2,3),但在有碰撞的情况下它不起作用,所以我必须管理碰撞。所以,我认为我正在做的

  • 我试图将动态元素添加到div中。Div有,但是如果添加到Div中的内容会被缩放,但也会被推送。 导致这一问题:如果数据很大,则“在小数据上更正一个”问题 我在网上试了很多东西,但我找不到任何关于这方面的信息。