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.