Wrapping fields
A FieldWrapper<T>
is a specialization of MutableField<T>
that allows the method setField()
. When this method is called passing a field instance, what it does is basically mirror its behavior, so when its value changes our FieldWrapper
value will also change.
This pattern is pretty useful when we want a class to accept both a field and an actual value. For instance, imagine we're developing a class similar to Android™'s TextView
. We could do something like this:
import com.femastudios.dataflow.*
import com.femastudios.dataflow.extensions.*
import com.femastudios.dataflow.listen.*
import com.femastudios.dataflow.util.*
class Movie(val name : MutableField<String>, val year : MutableField<Int>)
fun main() {
class TextView : BaseLifecycleOwner() {
//We implement BaseLifecycleOwner so we can attach listeners to our TextView
//This is the publicly available property to set the text in this TextView
val text = fieldWrapperOf("<no movie>") //Initial text
init {
//We listen to the changes in the text and draw it
listen(text) {
draw(it)
}
}
//Method to draw a string
private fun draw(str: String) {
println(str)
}
}
val avatar = Movie(mutableFieldOf("Avatar"), mutableFieldOf(2009))
val tv = TextView()
//All the following calls are valid
tv.text.value = "Hello world"
tv.text.setField(avatar.name) //avatar.name is a MutableField<String>
avatar.name.value = "Blue"
tv.text.value = "foo bar"
avatar.name.value = "Avatar"
//Outputs:
//<no movie>
//Hello world
//Avatar
//Blue
//foo bar
}
final class TextView extends BaseLifecycleOwner {
//We implement BaseLifecycleOwner so we can attach listeners to our TextView
@NotNull
@Override
public Map<Object, ListenerHolder<?>> getAttachedItems() {
return attachedItems;
}
//This is the publicly available property to set the text in this TextView
public final FieldWrapper<String> text = FieldWrapper.of("<no movie>"); //Initial text
public TextView() {
//We listen to the changes in the text and draw it
listen(text, this::draw);
}
//Method to draw a string
private void draw(String str) {
System.out.println(str);
}
}
Movie avatar = new Movie(MutableField.of("Avatar"), MutableField.of(2009));
TextView tv = new TextView();
//All the following calls are valid
tv.text.setValue("Hello world");
tv.text.setField(movie.name); //movie.name is a MutableField<String>
avatar.name.setValue("Blue");
tv.text.setValue("foo bar");
avatar.name.setValue("Avatar");
//Outputs:
//<no movie>
//Hello world
//Avatar
//Blue
//foo bar
When we set a value (e.g. "foo bar"
) the previous field is detached and the wrapper will not receive any more updates from it.
It is also possible to manually detach the field calling the method detachField()
: in this case the value will stay the same, but the wrapper will not receive any more updates.