First look
The main concept of this library are fields: a Field<T>
is an interface that holds a value of type T
and allows to register (and cancel) callbacks for data changes.
MutableField<T>
is an interface that builds on top of Field
, adding the possibility to change the value.
Here's a first example that shows how to construct fields:
import com.femastudios.dataflow.util.*
fun main() {
val field = mutableFieldOf(5) //Creates a mutable field of Int
println(field.value) //Outputs 5
field.value = 10 //Sets the value contained by the field to 10
println(field.value) //Outputs 10
}
MutableField<Integer> field = MutableField.of(5); //Creates a mutable field of Integer
System.out.println(field.getValue()); //Outputs 5
field.setValue(10); //Sets the value contained by the field to 10
System.out.println(field.getValue()) //Outputs 10
For more information see Creating fields.
There are three main ways to listen for changes in the field value:
- Strongly: a strong reference to the listener is kept until the
remove()
function is called. - Weakly: only a weak reference to the listener will be kept, allowing the garbage collector to reclaim it if all other references are lost. The caller is responsible for holding a strong reference to the callback.
- With lifecycle: the listener is active until the lifecycle owner is alive.
In the examples we'll use the strong version for simplicity's sake. Here's our first example:
import com.femastudios.dataflow.util.*
import com.femastudios.dataflow.listen.*
fun main() {
val field = mutableFieldOf(5)
field.listeners.addStrongly { newVal ->
print(newVal)
}
for(i in 1..5) {
field.value = i
}
//Output: 12345
}
MutableField<Integer> field = MutableField.of(5);
field.listeners().addStrongly((newData) -> {
System.out.print(newData);
};
for(int i = 1; i <= 5; i++) {
field.setValue(i);
}
//Output: 12345
For more information see Listening fields.
The real power of fields is unleashed when performing data manipulation. The main philosophy is that any transformation on fields will yield another Field
instance. In this way we can express all the transformations we want and keep fields around, allowing us to listen to changes in the original data that will propagate all the way down.
The following example demonstrates a basic usage of field manipulation:
import com.femastudios.dataflow.util.*
import com.femastudios.dataflow.listen.*
fun main() {
val number = mutableFieldOf(5)
val negation = number.transform { -it }
negation.listeners.addStrongly { newVal ->
print("$newVal ")
}
number.value = 7
number.value = -4
number.value = 1
//Output: -7 4 -1
}
MutableField<Integer> number = MutableField.of(5);
Field<Integer> negation = field.transform(v -> -v);
negation.listeners().addStrongly((newData) -> {
System.out.print(newData + " ");
});
number.setValue(7);
number.setValue(-4);
number.setValue(1);
//Output: -7 4 -1
The transform()
function returns a Field
: notice that it is not a mutable field and we cannot directly set a value.
For more information see Manipulating fields.