I am using the android data binding library and MVVM architecture. In the xml layout I define a variable named viewModel of type myViewModel. The layout has several TextInputEditText for which I used the following custom binding adapter:
//makes the drawable_right of the TextView clickable
@SuppressLint("ClickableViewAccessibility")
@BindingAdapter("onDrawableRightClick")
inline fun TextView.setOnDrawableRightClick(crossinline f: () -> Unit) {
this.setOnTouchListener(View.OnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_UP) {
if (event.rawX >= this.right - this.paddingRight - this.compoundDrawables[DRAWABLE_RIGHT].bounds.width()) {
f()
return@OnTouchListener true
}
}
false
})
}
In the layout I add app:onDrawableRightClick="@{() -> viewModel.doThing()}"
to just one of the TextInputEditText and click run. Everything works, no problem.
Now I go back and add app:onDrawableRightClick="@{() -> viewModel.doOtherThing()}"
to the second TextInputEditText. This time compilation fails with error: missing return statement
.
The error is in MyFragmentBindingImpl (generated), in this block of code:
public final kotlin.Unit _internalCallbackInvoke(int sourceId ) {
switch(sourceId) {
case 1: {
// localize variables for thread safety
// viewModel
com.example.MyViewModel viewModel = mViewModel;
// viewModel != null
boolean viewModelJavaLangObjectNull = false;
viewModelJavaLangObjectNull = (viewModel) != (null);
if (viewModelJavaLangObjectNull) {
viewModel.doOtherThing();
}
return null;
}
case 2: {
// localize variables for thread safety
// viewModel
com.example.MyViewModel viewModel = mViewModel;
// viewModel != null
boolean viewModelJavaLangObjectNull = false;
viewModelJavaLangObjectNull = (viewModel) != (null);
if (viewModelJavaLangObjectNull) {
viewModel.doThing();
}
return null;
}
}
}
There is neither a default case nor a return statement outside of the switch. This causes the error but I was pretty sure that the default case isn't necessary when every case is handled... Anyways, when I go back to xml and remove one of the listener bindings, MyFragmentBindingImpl changes to this:
public final kotlin.Unit _internalCallbackInvoke(int sourceId ) {
// localize variables for thread safety
// viewModel
com.example.MyViewModel viewModel = mViewModel;
// viewModel != null
boolean viewModelJavaLangObjectNull = false;
viewModelJavaLangObjectNull = (viewModel) != (null);
if (viewModelJavaLangObjectNull) {
viewModel.doThing();
}
return null;
}
The compiler is happy again, but I need to use the binding adapter more than once. How can I make the library add a return statement? Is there a workaround?
I'm using Android Studio 3.4 Preview. Thanks all
Binding adapters are responsible for making the appropriate framework calls to set values. One example is setting a property value like calling the setText() method. Another example is setting an event listener like calling the setOnClickListener() method.
Generated data binding code automatically checks for null values and avoid null pointer exceptions. For example, in the expression @{user.name} , if user is null, user.name is assigned its default value of null . If you reference user. age , where age is of type int , then data binding uses the default value of 0 .
As you've seen, there's no reason you can't use both Data Binding and View Binding on the same project. By default, the view binder compiler generates a binding class for each XML file. But, if you want to use Data Binding instead, you have to add the layout tag, as root, to the XML file.
ViewBinding vs DataBindingThe main advantages of viewbinding are speed and efficiency. It has a shorter build time because it avoids the overhead and performance issues associated with DataBinding due to annotation processors affecting DataBinding's build time.
@SuppressLint("ClickableViewAccessibility")
@BindingAdapter("onDrawableEndClick")
fun setOnDrawableEndClick(view: TextView, listener: OnCompoundDrawableClickListener?) {
val padding = 10
if (listener != null) {
view.setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
if (view.compoundDrawables[DRAWABLE_RIGHT] == null) return@setOnTouchListener false
else if (event.rawX >= (view.right - view.compoundDrawables[DRAWABLE_RIGHT].bounds.width() - padding)) {
listener.onDrawableEnd()
return@setOnTouchListener true
}
}
return@setOnTouchListener false
}
}
}
try something like this i am using a custom interface for the listener(OnCompoundDrawableClickListener)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With