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.

Registering listeners


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.

Field manipulation


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.