0

When trying to add data binding to my app, I see a crash after a ClassCastException inside MainActivityBinding. Here is the stack trace:

com.myapp E/AndroidRuntime: FATAL EXCEPTION: main
                                                                  Process: com.myapp, PID: 15524
                                                                  java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.CharSequence
                                                                      at com.mayapp.databinding.MainActivityBinding.executeBindings(MainActivityBinding.java:553)
                                                                      at android.databinding.ViewDataBinding.executeBindingsInternal(ViewDataBinding.java:379)
                                                                      at android.databinding.ViewDataBinding.executePendingBindings(ViewDataBinding.java:351)
                                                                      at android.databinding.ViewDataBinding$6.run(ViewDataBinding.java:178)
                                                                      at android.databinding.ViewDataBinding$5.onViewAttachedToWindow(ViewDataBinding.java:146)
                                                                      at android.view.View.dispatchAttachedToWindow(View.java:17392)
                                                                      at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3319)
                                                                      at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3326)
                                                                      at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3326)
                                                                      at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3326)
                                                                      at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1658)
                                                                      at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1386)
                                                                      at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6733)
                                                                      at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
                                                                      at android.view.Choreographer.doCallbacks(Choreographer.java:723)
                                                                      at android.view.Choreographer.doFrame(Choreographer.java:658)
                                                                      at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
                                                                      at android.os.Handler.handleCallback(Handler.java:789)
                                                                      at android.os.Handler.dispatchMessage(Handler.java:98)
                                                                      at android.os.Looper.loop(Looper.java:164)
                                                                      at android.app.ActivityThread.main(ActivityThread.java:6541)
                                                                      at java.lang.reflect.Method.invoke(Native Method)
                                                                      at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
                                                                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

Inside main_activity.xml I have the following:

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

    <data>
        <variable
            name="tiles"
            type="com.myapp.Tile[]" />
    </data>
    ...

Tile[] is underlined giving me the "Cannot resolve symbol ..." error which I chose to ignore since the docs say:

Note: Arrays and a generic type, such as the Observable class, might display errors when there are no errors.

The gradle build is successful, however, when I run the app on an emulator or on a physical device I get the above error.

When I follow the link from the stack trace I can actually enter MainActivityBinding. Among a lot of code I find the following method marked by the compiler:

public boolean setVariable(int variableId, Object variable) {
    switch(variableId) {
        case BR.tiles :
            setTiles((com.myapp.Tile[]) variable);
            return true;
    }
    return false;
}

BR.tiles is underlined and the compiler tells me: "Constant expression required".

Is this a bug or am I doing something wrong?

kalabalik
  • 3,792
  • 2
  • 21
  • 50
  • The `BR.tiles` part most likely is unavoidable; use `if` instead of `switch`. With regards to the crash, you have a binding expression that is evaluating to an `int` or `Integer` on some attribute that needs a `CharSequence`. – CommonsWare Oct 24 '17 at 10:40
  • The error is inside the auto-generated `MainActivityBinding`. I can't change the code there, right? – kalabalik Oct 24 '17 at 10:51
  • Also, I checked: `BR.tiles` is `public static final int`. So why does the compiler complain anyway? – kalabalik Oct 24 '17 at 10:54
  • @CommonsWare The other part of your comment led me on the right track. I had the following expression inside my XML: `android:text='@{tiles[0].getValue == 0 ? "" : tiles[0].getValue}'` in order to print nothing if value == 0 else print value. Yet the "false side" of the ternary evaluates to an int. I put String.valueOf(tiles[0].getValue) and it works. Care for some more rep? Probably not, but if so, write an answer, I will check and upvote it. – kalabalik Oct 24 '17 at 11:12

2 Answers2

2

When trying to add data binding to my app, I see a crash after a ClassCastException inside MainActivityBinding.

Based on the error, you have a binding expression that evaluates to an int or Integer, but the attribute is expecting a CharSequence.

I had the following expression inside my XML: android:text='@{tiles[0].getValue == 0 ? "" : tiles[0].getValue}' in order to print nothing if value == 0 else print value. Yet the "false side" of the ternary evaluates to an int. I put String.valueOf(tiles[0].getValue) and it works.

Usually, if you pass an int to android:text via a binding expression, it compiles fine, but then if the int is not a string resource ID, you crash on that (ResourceNotFoundException). My guess is that the data binding framework is assuming that you want setText(CharSequence) due to the "" and is explicitly casting the ternary result to CharSequence, which then crashes when an Integer cannot be cast that way.

Personally, I am moving away from using this sort of binding expression, instead populating some sort of true "view model" where this logic is in Java (easier to debug, easier to test) and binding against it, so the binding expressions are simpler.

I checked: BR.tiles is public static final int. So why does the compiler complain anyway?

That's a good question. I had assumed that it was declared in such a way that switch did not like.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
0

Define the variable of type integer like,

<data>
<integer
        name="tiles">integer
</integer>
</data>

as you are assigning integer value to XML variable.

Maaz Patel
  • 756
  • 2
  • 7
  • 20
  • Compiler: "Element integer not allowed here" (even without the "free" integer inside the element). My variables are not integers anyway. It is an array of my custom-made `Tile`. – kalabalik Oct 24 '17 at 10:33
  • Please refer this link : https://stackoverflow.com/questions/6774579/typearray-in-android-how-to-store-custom-objects-in-xml-and-retrieve-them Let me is it helpful or not. – Maaz Patel Oct 24 '17 at 10:37
  • The link is not helpful. The question there is about how to make a array from resources. My question is about data binding. There is no direct relationship. – kalabalik Oct 24 '17 at 10:47