Here is the code:
package sample;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
/**
* Created by IDEA on 29/07/15.
*/
public class ListPropertyTest {
public static void main(String[] args) {
ListProperty<String> lp =
new SimpleListProperty<>(FXCollections.observableArrayList());
lp.addListener(new ListChangeListener<String>() {
@Override
public void onChanged(Change<? extends String> c) {
while(c.next()) {
String action = c.wasPermutated() ? "perm"
: c.wasUpdated() ? "upd"
: c.wasRemoved() ? "rem"
: c.wasAdded() ? "add" : "";
System.out.println("Action: " + action);
System.out.println("Removed: " + c.getRemoved());
System.out.println("Added: " + c.getAddedSubList());
}
}
});
lp.addListener(new ChangeListener<ObservableList<String>>() {
@Override
public void changed(ObservableValue<? extends ObservableList<String>> observable, ObservableList<String> oldValue, ObservableList<String> newValue) {
System.out.println("List changed.");
System.out.println("Old: " + oldValue);
System.out.println("New: " + newValue);
}
});
lp.addListener(new InvalidationListener() {
@Override
public void invalidated(Observable observable) {
System.out.println("List invalid");
}
});
System.out.println("Add =========");
lp.addAll("one", "two");
System.out.println("Set =========");
lp.set(FXCollections.observableArrayList("two", "three"));
System.out.println("Remove ============");
lp.remove("two");
}
}
Result:
Add =========
List invalid
List changed.
Old: [one, two]
New: [one, two]
Action: add
Removed: []
Added: [one, two]
Set =========
List invalid
List changed.
Old: [one, two]
New: [two, three]
Action: rem
Removed: [one, two]
Added: [two, three]
Remove ============
List invalid
List changed.
Old: [three]
New: [three]
Action: rem
Removed: [two]
Added: []
As you can see, the change listener behaved correctly only in the "Set" part.
答案 0 :(得分:2)
Most of this is intended behavior.
A function(error) {
if(error.code == 0){
// unknown error
} else if(error.code == 1) {
// permission denied
} else if(error.code == 2) {
// position unavailable
} else if(error.code == 3) {
// timeout
}
console.log(error.message);
},
is both an ListProperty
and an ObjectProperty<ObservableList>
.
Being an ObservableList
means it wraps (contains a reference to) an ObjectProperty<ObservableList>
and has ObservableList
(or setValue(ObservableList)
) and set(...)
methods. As an getValue()
, you can register a ObjectProperty<ObservableList>
with it. If the reference to the wrapped list changes, by someone calling ChangeListener<ObservableList>
, the setValue(ObservableList)
method gets called on any registered ChangeListener<ObservableList>.changed(...)
, passing in a reference to the ChangeListener
itself, the old ListProperty
reference, and the new ObservableList
reference. You see this behavior when you call ObservableList
in your code.
When you simply change the content of the list, however, the wrapped list is still the same physical object. So the "old list" and the "new list" are one and the same. It is a bug that the change listener fires notifications in this case; hat-tip to @kleopatra for pointing this out.
A set
also implements ListProperty
, by delegating the ObservableList
method calls to the wrapped list instance. This means if the content of the list change, any ObservableList
s registered with the ListChangeListener
get notified. Again, note in this case that there is only one list object; it's just that its contents have been modified.
You can get details about changes that occur to an ListProperty
via the ObservableList
object passed to the Change
method, as you observe in the output from your onChanged(...)
method. Note that onChanged
and c.getFrom()
will give you the indexes of the items that have changed as well.
I almost never have a need for a c.getTo()
: in the vast majority of use cases it is enough for me to just use a plain ListProperty
implementation. Controls that are based on lists of objects (such as ObservableList
and ListView
) use them, so you can call TableView
to pass in an existing setItems(...)
if you need, or (probably more usually) you can just call ObservableList
to retrieve the current list and modify it. As you can see from the explanation above, the getItems()
allows these controls to observe either kind of change. But it is likely that in your own code, you will use ListProperty
directly far more often than you use a ObservableList
.