AaronJ
AaronJ

Reputation: 714

Android Data Binding: Missing return statement in generated code when calling custom binding adapter more than once

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

Upvotes: 18

Views: 3061

Answers (2)

ThaiBao
ThaiBao

Reputation: 113

I know that we already have an answer to this question already, and this is a pretty old topic. But when I tried the first solution in my case, I had to create too many unnecessary interfaces, so I came up with another solution here:

In the view model, instead of :

fun doThing() {/* Do thing */}
fun doOtherThing() {/* Do other thing */}

I changed it to:

val doThing: () -> Unit = {/* Do thing */}
val doOtherThing: () -> Unit = {/* Do other thing */}

Then in the XML file:

...
app:onDrawableRightClick="@{viewModel.doThing}"
...
app:onDrawableRightClick="@{viewModel.doOtherThing}"

It works fine in my case, hope it could help someone.

Upvotes: 1

Abraham Mathew
Abraham Mathew

Reputation: 2146

@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)

Upvotes: 11

Related Questions