Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error when attempting to use the data binding provided context variable with BaseObservable

Per this comment and the Android Data Binding tutorial I should have a context variable available when data binding:

A special variable named context is generated for use in binding expressions as needed. The value for context is the Context from the root View's getContext(). The context variable will be overridden by an explicit variable declaration with that name.

I'm using a class extending BaseObservable to set my data, but no matter how I try to bring in the context variable in my @Bindable method I get the compile time error:

java.lang.RuntimeException: failure, see logs for details. @Bindable associated with method must follow JavaBeans convention getStyledName(android.content.Context)

As far as I can tell, I am following JavaBeans conventions. I've tracked the error down to this line in BrUtil but that didn't give me much help either.

I've tried changing my method and parameter names, I've tried adding in a <variable> for the context and a <import> for android.content.Context, but none of that made any difference. My User.java below has two @Bindable methods, the bare getName() works fine but the one that tries to use the context variable doesn't, so I don't think it's an issue with the rest of my data binding setup either.

Relevant code:

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable name="user" type="com.kasra.androidsandbox.User" />
    </data>

    <LinearLayout
        android:id="@+id/main_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <android.support.v7.widget.Toolbar
            android:id="@+id/main_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            android:minHeight="?attr/actionBarSize"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

        <TextView
            android:id="@+id/main_textview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="@{user.getStyledName(context)}" />
    </LinearLayout>
</layout>

User.java:

public class User extends BaseObservable {
    private String name;

    public User(String name) {
        this.name = name;
    }

    @Bindable
    public String getName() {
        return this.name;
    }

    @Bindable
    public CharSequence getStyledName(Context ctx) {
        int color = ctx.getResources().getColor(R.color.branded_pink);

        Spannable textSpan = new SpannableString(name);
        textSpan.setSpan(new ForegroundColorSpan(color), 0, textSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

        return textSpan;
    }

}

MainActivity.java:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    User user = new User("Kasra");
    binding.setUser(user);

    Toolbar toolbar = (Toolbar) findViewById(R.id.main_toolbar);
    setSupportActionBar(toolbar);
}
like image 203
Kasra Rahjerdi Avatar asked Aug 22 '16 19:08

Kasra Rahjerdi


Video Answer


1 Answers

I don't know whether this is a bug or intended behavior, but I observed this behavior myself, so you're not crazy.

A workaround is to create a method that is NOT marked @Bindable in your User -- the one that requires the Context. This method won't be subject to the JavaBeans naming conventions.

Important: In order to make sure it's updated appropriately, it should take as inputs any @Bindable fields that might change.

User.java

public class User extends BaseObservable {
    private String name;

    public User(String name) {
        this.name = name;
    }

    @Bindable
    public String getName() {
        return this.name;
    }

    public CharSequence getStyledName(Context ctx, String name) {
        // construct styled name here
    }
}

and in your layout:

<TextView
        android:id="@+id/main_textview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="@{user.getStyledName(context, user.name)}" />
like image 190
Lisa Wray Avatar answered Sep 19 '22 22:09

Lisa Wray