假设我们有一个ObservableList<Person>
,其中Person有属性:年龄,性别。目标是创建一个类似于的可观察(在所有级别)地图
Map<Gender, Map<Age, List<Person>>>
我可以绑定到ObservableList
。
这样做的原因是因为我必须根据这样的分组提取实时聚合数据。
答案 0 :(得分:1)
这要求您为每个属性添加一个侦听器,并为属性指定bean,以避免为每个Person
创建两个侦听器:
private final ObjectProperty<Gender> gender = new SimpleObjectProperty<>(this, "gender");
private final IntegerProperty age = new SimpleIntegerProperty(this, "age");
public static void main(String[] args) {
ObservableList<Person> data = FXCollections.observableArrayList();
ObservableMap<Gender, ObservableMap<Number, ObservableList<Person>>> grouped = FXCollections.observableHashMap();
ChangeListener<Gender> genderChangeListener = (observable, oldValue, newValue) -> {
ObservableMap<Number, ObservableList<Person>> m = grouped.get(oldValue);
Person person = (Person) ((Property) observable).getBean();
// remove person from list and remove list, if it becomes empty
m.compute(person.getAge(), (a, lp) -> {
lp.remove(person);
return lp.isEmpty() ? null : lp;
});
// remove age map, if it's empty
if (m.isEmpty()) {
grouped.remove(oldValue);
}
// add person at new position generating the Map/List, if necessary
grouped.computeIfAbsent(newValue, g -> FXCollections.observableHashMap())
.computeIfAbsent(person.getAge(), a -> FXCollections.observableArrayList())
.add(person);
};
ChangeListener<Number> ageChangeListener = (observable, oldValue, newValue) -> {
Person person = (Person) ((Property) observable).getBean();
ObservableMap<Number, ObservableList<Person>> map = grouped.get(person.getGender());
// remove person from list and remove list, if it becomes empty
map.compute(oldValue, (a, lp) -> {
lp.remove(person);
return lp.isEmpty() ? null : lp;
});
// add person at new position generating the List, if necessary
map.computeIfAbsent(newValue, a -> FXCollections.observableArrayList())
.add(person);
};
data.addListener((ListChangeListener.Change<? extends Person> c) -> {
while (c.next()) {
for (Person p : c.getRemoved()) {
// unregister the listeners of removed Persons
p.genderProperty().removeListener(genderChangeListener);
p.ageProperty().removeListener(ageChangeListener);
// remove person from grouped
ObservableMap<Number, ObservableList<Person>> m = grouped.get(p.getGender());
m.compute(p.getAge(), (a, lp) -> {
lp.remove(p);
return lp.isEmpty() ? null : lp;
});
if (m.isEmpty()) {
grouped.remove(p.getGender());
}
}
for (Person p : c.getAddedSubList()) {
// add listeners to person
p.genderProperty().addListener(genderChangeListener);
p.ageProperty().addListener(ageChangeListener);
// add person to grouped generating the Map/List, if necessary
grouped.computeIfAbsent(p.getGender(), g -> FXCollections.observableHashMap())
.computeIfAbsent(p.getAge(), a -> FXCollections.observableArrayList())
.add(p);
}
}
});
// test
Person p = new Person("Frank", Gender.MALE, 20);
Person p2 = new Person("Lisa", Gender.FEMALE, 32);
Person p3 = new Person("Nora", Gender.FEMALE, 52);
Person p4 = new Person("Carl", Gender.MALE, 62);
System.out.println(grouped);
data.addAll(p, p2, p3, p4);
System.out.println(grouped);
p3.setAge(32);
System.out.println(grouped);
p.setGender(Gender.FEMALE);
System.out.println(grouped);
data.remove(p3);
System.out.println(grouped);
data.remove(p4);
System.out.println(grouped);
}