Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Databinding: Bind single method from listener with multiple methods

Yigit Boyar and George Mount members of the Android UI Toolkit team gave a talk on databinding. In the video at 13:41 George Mount says this

You can also do some of the weird listeners, like onTextChanged. TextWatcher has three methods on it, but everybody only cares about onTextChanged, right? You can actually access just one of them if you want, or all of them."

<Button android:onTextChanged="@{handlers.textChanged}" …/>

He seemed to be saying that instead of using the usual addTextChangedListener method that looks something like this

editText.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        //Do something
    }

    @Override
    public void afterTextChanged(Editable editable) {}
});

we could simply do this

<EditText 
    android:onTextChanged="@{handlers::onTextChanged}"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

Handlers class

public class Handlers{
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        //Do something
    }
}

The code works in this instance, but it doesn't seem to work in other cases where the listener has multiple methods like ViewPager's addOnPageChangeListener method. For example this doesn't work

<android.support.v4.view.ViewPager
    android:OnPageSelected="@{handlers::onPageSelected}"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

and the Handlers class

public class Handlers{
    public void onPageSelected(int position) {
        //Do something
    }
}

The project spits out this error when trying to build

Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> java.lang.RuntimeException: Found data binding errors.
****/ data binding error ****msg:Could not resolve handlers::onPageSelected as a listener.

****\ data binding error ****

I'm a bit confused now because it turns out that EditText actually has an inherited onTextChanged method which the databinding library can also bind android:onTextChanged="@{handlers::onTextChanged}" to.

So my question is that is it actually possible to bind to a single listener method and I'm missing something, or did George Mount make a mistake in his talk?

like image 837
Olumide Avatar asked Aug 30 '16 11:08

Olumide


1 Answers

Let's hope that it wasn't a mistake in the talk :-)

It looks like we didn't implement it for ViewPager. The implementation is not too difficult. There is a trick -- you must declare a single interface for each matching method.

public interface OnPageScrollStateChanged {
    void onPageScrollStateChanged(int state);
}
public interface OnPageScrolled {
    void onPageScrolled(int position, float offset, int offsetPixels);
}
public interface OnPageSelected {
    void onPageSelected(int position);
}

Then the binding adapter should be created for the events:

@BindingAdapter(value = {"android:onPageScrollStateChanged",
                         "android:onPageScrolled",
                         "android:onPageSelected"}, requireAll=false)
public static void setViewPagerListeners(ViewPager view,
        final OnPageScrollStateChanged scrollStateChanged,
        final OnPageScrolled scrolled,
        final OnPageSelected selected) {
    OnPageChangeListener newListener = null;
    if (scrollStateChanged != null || scrolled != null || selected != null) {
        newListener = new OnPageChangeListener() {
            @Override
            public void onPageScrollStateChanged(int state) {
                if (scrollStateChanged != null) {
                    scrollStateChanged.onPageScrollStateChanged(state);
                }
            }
            // similar with the other two methods ...
        };
    }

    OnPageChangeListener oldListener = ListenerUtil.trackListener(view,
        newListener, R.id.viewPagerListener);
    if (oldListener != null) {
        view.removeOnPageChangeListener(oldListener);
    }
    if (newListener != null) {
        view.addOnPageChangeListener(newListener);
    }
}
like image 102
George Mount Avatar answered Nov 04 '22 03:11

George Mount