Error trying to use data binding to context variable using BaseObservable

Per this comment and Android Data Binding Tutorial . I need to have a context variable available when binding data:

A special variable called context is generated for use in required expressions as needed. The value for the context is the context from the root of the view getContext (). A context variable will be overridden by an explicit declaration of a variable with this name.

I use a class that extends BaseObservable to set my data, but no matter how I try to introduce the context variable into my @Bindable method, I get a compile-time error:

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

As far as I can tell, I follow the JavaBeans conventions. I tracked the error to this line in BrUtil , but that didn't help me either.

I tried changing my method and parameter names, I tried adding in <variable> for context and <import> for android.content.Context , but none of them mattered. My User.java below has two @Bindable methods, bare getName() works fine, but one that tries to use the context variable does not do this, so I don't think this is a problem with the rest of my binding data.

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); } 
+5
source share
2 answers

I do not know if this is a mistake or an alleged behavior, but I myself observed this behavior, so you are not crazy.

The workaround is to create a method that is NOT tagged @Bindable in your user — one that requires context. This method will not obey JavaBeans naming conventions.

It is important . To ensure that it is updated appropriately, it must accept any @Bindable fields that may change as input.

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)}" /> 
+13
source

Since Android 2.3 , you can declare a field in which your @Bindable function depends on the @Bindable annotation.

 @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Bindable { String[] value() default {}; } 

In your case, you should write your function as follows

 @Bindable("name") public CharSequence getStyledName(Context ctx) { // your existing code } 

See https://medium.com/google-developers/android-data-binding-dependent-properties-516d3235cd7c

0
source

All Articles