I have a CustomView class with a databound layout that takes a variable. In the layout that contains the CustomView, I want to pass an attribute into the CustomView, and have that CustomView pass that attribute into its own layout's binding. Here's what I have:
public class CustomView extends LinearLayout
{
public CustomView(Context inContext, AttributeSet inAttrs)
{
super(inContext, inAttrs);
inflate(inContext, R.layout.custom_view, null);
}
@BindingAdapter({"app:variable"})
public static void SetVariable(CustomView inCustomView, VariableType inMyVariable)
{
CustomViewBinding binding = DataBindingUtil.getBinding(inCustomView);
binding.setMyVariable(inMyVariable);
}
}
This crashes trying to extract the binding from the view. Is this even possible? Here is the stack trace:
java.lang.NullPointerException: Attempt to invoke virtual method 'void xxx.databinding.CustomViewBinding.setVariableType(xxx.VariableType)' on a null object reference
at xxx.CustomView.SetDynamicList(CustomView.java:32)
at xxx.MyFragmentBinding.executeBindings(MyFragmentBinding.java:116)
at android.databinding.ViewDataBinding.executePendingBindings(ViewDataBinding.java:350)
at android.databinding.ViewDataBinding$6.run(ViewDataBinding.java:167)
at android.databinding.ViewDataBinding$7.doFrame(ViewDataBinding.java:233)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:856)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:603)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
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)
And if I change
DataBindingUtil.getBinding(inCustomView)
to
DataBindingUtil.bind(inCustomView)
then I get this:
java.lang.IllegalArgumentException: View is not a binding layout
at android.databinding.DataBindingUtil.bind(DataBindingUtil.java:166)
at android.databinding.DataBindingUtil.bind(DataBindingUtil.java:140)
at xxx.CustomView.SetDynamicList(CustomView.java:30)
- at xxx.databinding.MyFragmentBinding.executeBindings(MyFragmentBinding.java:116)
at android.databinding.ViewDataBinding.executePendingBindings(ViewDataBinding.java:350)
at android.databinding.ViewDataBinding$6.run(ViewDataBinding.java:167)
at android.databinding.ViewDataBinding$7.doFrame(ViewDataBinding.java:233)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:856)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:603)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
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)
This might imply that the layout file is not formatted for databinding, but it is. It has the layout element, and the data element with variables and everything.
In the include layout you must create a Container layout and put here the id. Show activity on this post. private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super. onCreate(savedInstanceState) binding = DataBindingUtil.
To enable view binding, configure viewBinding in your module-level build. gradle file. Once enabled for a project, view binding will generate a binding class for all of your layouts automatically. You don't have to make changes to your XML — it'll automatically work with your existing layouts.
The above layout filename is activity_main. xml so the corresponding generated class is ActivityMainBinding . This class holds all the bindings from the layout properties (for example, the user variable) to the layout's views and knows how to assign values for the binding expressions.
You must bind the inflated view to create the data binding. In your example, you're binding the container of the layout.
You can do this in several ways. The easiest is to bind it as part of inflation:
public class CustomView extends LinearLayout
{
CustomViewBinding mBinding;
public CustomView(Context inContext, AttributeSet inAttrs)
{
super(inContext, inAttrs);
LayoutInflater inflater = LayoutInflater.from(inContext);
// I assume you want it inflated into this ViewGroup
mBinding = CustomViewBinding.inflate(inflater, this, true);
}
public void setVariable(CustomView inCustomView, VariableType inMyVariable) {
mBinding.setVariable(inMyVariable);
}
...
}
You don't really need a binding adapter unless you don't want the setter as part of your custom view. In that case, you'll still need a way to get the binding, so you'll need to add something like this:
public CustomViewBinding getBinding() { return mBinding; }
so that your binding adapter works.
If you know that the LinearLayout contents are all going to be from the inflated view, you can use a binding adapter like this:
@BindingAdapter({"app:variable"})
public static void setVariable(CustomView inCustomView, VariableType inMyVariable)
{
if (inCustomView.getChildCount() == 0) {
return;
}
View boundView = inCustomView.getChildAt(0);
CustomViewBinding binding = DataBindingUtil.getBinding(boundView);
binding.setMyVariable(inMyVariable);
}
If your custom view isn't very custom, you can simply include your layout directly:
<include layout="@layout/custom_view" app:variable="@{myVariableValue}"/>
You would, of course, have to move the LinearLayout into the custom_view.xml.
Basically, this is how it worked for me:
XML:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/containerView"
xmlns:tools="http://schemas.android.com/tools">
.....
</layout>
Java Class:
GeneralOverviewBinding binding = DataBindingUtil.bind((findViewById(R.id.containerView)));
This basically returns the binding for the given layout root or creates a binding if one does not exist.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With