novachevskyi
novachevskyi

Reputation: 183

Android Data Binding crash when using include tag with custom view layout

I'm trying to add some custom view using include tag to my activity layout which using DataBinding. My custom view is using DataBinding as well. But I got crash on application start:

05-02 17:30:03.685 12595-12595/? E/AndroidRuntime: FATAL EXCEPTION: main
                                                   Process: com.novachevskyi.databindingtest, PID: 12595
                                                   java.lang.RuntimeException: Unable to start activity ComponentInfo{com.novachevskyi.databindingtest/com.novachevskyi.databindingtest.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.novachevskyi.databindingtest.databinding.CustomViewBinding.invalidateAll()' on a null object reference
                                                       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
                                                       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
                                                       at android.app.ActivityThread.-wrap11(ActivityThread.java)
                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
                                                       at android.os.Handler.dispatchMessage(Handler.java:102)
                                                       at android.os.Looper.loop(Looper.java:148)
                                                       at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                       at java.lang.reflect.Method.invoke(Native Method)
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                                                    Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.novachevskyi.databindingtest.databinding.CustomViewBinding.invalidateAll()' on a null object reference
                                                       at com.novachevskyi.databindingtest.databinding.ActivityMainBinding.invalidateAll(ActivityMainBinding.java:41)
                                                       at com.novachevskyi.databindingtest.databinding.ActivityMainBinding.<init>(ActivityMainBinding.java:33)
                                                       at com.novachevskyi.databindingtest.databinding.ActivityMainBinding.bind(ActivityMainBinding.java:105)
                                                       at android.databinding.DataBinderMapper.getDataBinder(DataBinderMapper.java:11)
                                                       at android.databinding.DataBindingUtil.bind(DataBindingUtil.java:185)
                                                       at android.databinding.DataBindingUtil.bindToAddedViews(DataBindingUtil.java:299)
                                                       at android.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:279)
                                                       at android.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:261)
                                                       at com.novachevskyi.databindingtest.MainActivity.onCreate(MainActivity.java:11)
                                                       at android.app.Activity.performCreate(Activity.java:6251)
                                                       at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
                                                       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
                                                       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
                                                       at android.app.ActivityThread.-wrap11(ActivityThread.java) 
                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
                                                       at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                       at android.os.Looper.loop(Looper.java:148) 
                                                       at android.app.ActivityThread.main(ActivityThread.java:5417) 
                                                       at java.lang.reflect.Method.invoke(Native Method) 
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

MainActivity:

public class MainActivity extends AppCompatActivity {
  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    DataBindingUtil.setContentView(this, R.layout.activity_main);
  }
}

CustomView:

public class CustomView extends LinearLayout {
  public CustomView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  @Override protected void onFinishInflate() {
    super.onFinishInflate();
    DataBindingUtil.bind(this);
  }
}

activity_main.xml:

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

  <RelativeLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:paddingLeft="@dimen/activity_horizontal_margin"
      android:paddingRight="@dimen/activity_horizontal_margin"
      android:paddingTop="@dimen/activity_vertical_margin"
      android:paddingBottom="@dimen/activity_vertical_margin"
      tools:context="com.novachevskyi.databindingtest.MainActivity">

    <include layout="@layout/custom_view"/>

  </RelativeLayout>

</layout>

custom_view.xml:

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

  <com.novachevskyi.databindingtest.CustomView
      android:layout_width="match_parent"
      android:layout_height="match_parent">

    <TextView
        android:text="Hello World!"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

  </com.novachevskyi.databindingtest.CustomView>

</layout>

I've also created public repo with sample project: https://github.com/novachevskyi/DataBinding-issue

I was using data binding with com.android.tools.build:gradle:1.3.1 and now, when I've tried to upgrade build tools version to com.android.tools.build:gradle:2.1.0, I'm facing such issue with all my views that contain include xml tag. Will appreciate for any information about issue described above.

Upvotes: 12

Views: 6775

Answers (5)

touhid udoy
touhid udoy

Reputation: 4442

For me, the crash was due using same id (@+id/progress_bar) in both include tag and in the layout file.

activity layout

<include **android:id="@+id/progress_bar"** layout="@layout/progress_bar" />

progress_bar.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">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ProgressBar
            android:id="@+id/progress_bar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

when I change activity layout like this, it was fixed

<include **android:id="@+id/pb"** layout="@layout/progress_bar" />

Upvotes: 0

Rohan Mehrotra
Rohan Mehrotra

Reputation: 1

Goto Build option in toolbar and select Rebuild Project.

Upvotes: -1

jacoballenwood
jacoballenwood

Reputation: 3057

In case anyone else makes the er..dumb mistake I did...

This error was happening to me when I mistakenly had two duplicate layout files, one using databinding, and the other not...

Removing the duplicate fixed the error for me.

Upvotes: 2

Henry
Henry

Reputation: 1479

@SeptimusX75's answer doesn't work, because DataBindingUtil.findBinding(this) calls this.getTag(R.id.dataBinding) internally to get the binding, but the tag hasn't been set yet when onFinishInflate is called.

Instead, try to get the binding via this.getTag(R.id.dataBinding); when you need the use the binding.

public class CustomView extends LinearLayout {
    // ...
    public CustomViewBinding binding;
    // ...
    public void setTitle(final String text) {
        if (binding == null) {
            binding = Objects.requireNonNull(getTag(R.id.dataBinding));
        }
        binding.title.setText(text);
    }
}

Alternatively, set the binding manually from the activity before calling any method on the CustomView.

public class CustomView extends LinearLayout {
    // ...
    public CustomViewBinding binding;
    // ...
    public void setBinding(final CustomViewBinding binding) {
        this.binding = binding;
    }
}
public class MainActivity extends AppCompatActivity {
    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        CustomViewBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.customView.getRoot().setBinding(binding.customView);
    }
}

Upvotes: -1

SeptimusX75
SeptimusX75

Reputation: 2195

I took a look at your project and ran it. I think the reason it is crashing is because of

@Override protected void onFinishInflate() {
    super.onFinishInflate();
    DataBindingUtil.bind(this);
}

if you remove DataBindingUtil.bind(this) it will stop crashing. The reason being that the bind call is looking for a <layout>surrounding the view but it can't find it so it throws an exception. Since the CustomView is calling bind on itself it is not surrounded by anything causing ViewDataBinding to throw new IllegalArgumentException("View is not a binding layout")

I'm not entirely sure what you're trying to achieve but calling bind inside of onFinishInflate would be redundant since the activity is doing that for you when it binds the layout for the activity. If you require the binding within the CustomView class you can do the following:

@Override protected void onAttachedToWindow() {
  super.onAttachedToWindow();
  CustomViewBinding binding = DataBindingUtil.findBinding(this);
}

Upvotes: 4

Related Questions