Databinding Code Formatting Standards
Variables
If having one-way databinding provide an immutable reference
class FeatureViewModel : ViewModel() {
private val _name = MutableLiveData("joe")
val name: LiveData<String>
get() = _name
}
If any variable can potentially raise an NPE, the compiler will provide a warning describing to unbox the variable
so it is safely treated. Make sure to unbox it or provide a custom data binder adapter which accepts nullables.
android:text="@{safeUnbox(viewModel.name)}"
Here is a custom binding adapter handling a nullable string
@BindingAdapter("safeText")
fun safeText(textView: TextView, value: String?) {
value?.let {
textView.text = value
}
}
app:safeText="@{viewModel.name}"
Databinders should stay away from having logic placed inline as much as possible. Have the ViewModel
supply a variable which retains the logic, and is also useful to test.
app:visibleOrGone="@{safeUnbox(viewModel.name.length()==0?false:true)}"
instead
app:visibleOrGone="@{viewModel.isNameAvailable}"
Custom Databinders
- Make your Android components lighter by bringing repeated UI logic into a custom Databinder
@BindingAdapter("editorActionDone")
fun setEditorActionDone(editText: EditText, listener: (() -> Unit)?) {
listener?.let {
editText.setOnEditorActionListener { _, actionId, event ->
if ((event != null && (event.keyCode == KeyEvent.KEYCODE_ENTER)) ||
(actionId == EditorInfo.IME_ACTION_DONE)) {
it.invoke()
}
false
}
}
}
app:editorActionDone="@{viewModel::onNameSubmitted}"
- Avoid making several databinders based on combinations instead use
requireAll = false
to make them optional.
@BindingAdapter(value = [
"glideSrc",
"glideErrorHolder",
"glideCornerRadius",
"glideTransformation",
"glideOnLoadStatus"
],
requireAll = false
)
<ImageView
android:id="@+id/feature_profile_image"
android:layout_width="@dimen/profile_image_width"
android:layout_height="wrap_content"
android:contentDescription="@{viewModel.contentDescription}"
app:glideSrc="@{viewModel.imgUrl}"/>