Databinding error - Could not find accessor - android

I googled but still didn't find solution for me.
This is my xml:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import
alias="noteViewModel"
type="com.app.screen.createnote.CreateNoteViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="#+id/etNote"
style="#style/JWidget.EditText.Grey"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="start"
android:inputType="textMultiLine"
android:scrollbars="vertical"
android:text="#={noteViewModel.note.description}" />
</LinearLayout>
</layout>
This is my ViewModel code:
public class CreateNoteViewModel extends BaseObservable {
private Note note;
#Bindable
public Note getNote() {
return note;
}
public void setNote(Note note) {
this.note = note;
notifyPropertyChanged(BR.note);
}
}
But when I try run my app I got it:
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
java.lang.RuntimeException: Found data binding errors.
****/ data binding error ****msg:Could not find accessor com.justsafe.tmgr.justsafe.screen.createnote.CreateNoteViewModel.note
file:C:\android\work\JustSafeTmgr\app\src\main\res\layout\activity_create_note.xml
loc:44:33 - 44:62
****\ data binding error ****
P.S. In other place in my app it work, but there I get problem.

Try to change the <import> tag to a <variable> tag:
<data>
<variable
name="noteViewModel"
type="com.app.screen.createnote.CreateNoteViewModel" />
</data>

build.gradle -- app
android {
dataBinding {
enabled = true
}
}
dependencies {
def life_versions = "1.1.1"
// Lifecycle components
implementation "android.arch.lifecycle:extensions:$life_versions"
annotationProcessor "android.arch.lifecycle:compiler:$life_versions"
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="LoginViewModel"
type="com.keshav.mvvmdemokeshav.viewModel.LoginViewModel" />
</data>
<!-- TODO Your XML File-->
</layout>

Related

setting a customView variable while databinding

I'm trying to set a variable (buttonText) of customView from main_activity.xml but I got this error:
attribute buttonText (aka com.example.testbinding:buttonText) not
found. error: failed linking file resources.
customView.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="buttonText"
type="String" />
</data>
<LinearLayout
android:id="#+id/container"
android:orientation="vertical">
<Button
android:id="#+id/button"
android:text="#{buttonText}" />
</LinearLayout>
</layout>
main_activity.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>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.testbinding.CustomView
android:id="#+id/customView"
...
app:buttonText = "Test button text"
...
>
</com.example.testbinding.CustomView>
</android.support.constraint.ConstraintLayout>
</layout>
In this post I found:
In your Custom View, inflate layout however you normally would and
provide a setter for the attribute you want to set:
My CustomView class have a public setter for buttonText property:
public class CustomView extends LinearLayout {
private CustomViewBinding binding;
private String buttonText;
public CustomView(Context context) {
super(context);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
binding = DataBindingUtil.inflate(inflater, R.layout.custom_view, this, true);
}
public String getButtonText() {
return buttonText;
}
public void setButtonText(String buttonText) {
this.buttonText = buttonText;
}
}
Can anyone tell me what's wrong with it?
Or it impossible without BindingAdapter?
binding.setbuttonText("text_button");
instead of
public String getButtonText() {
return buttonText;
}
public void setButtonText(String buttonText) {
this.buttonText = buttonText;
}
Seems I found what was wrong.
If I use a variable declared in parent view - everything is ok. But if I use a value right in property it's don't work.
wrong:
app:buttonText = "Test button text"
app:progressValue = "50"
correct:
<variable
name="viewModel"
type="com.example.testbinding.ViewModel"/>
app:buttonText = "#{viewModel.buttonText}"
app:progressValue = "#{viewModel.progressValue}"
Of course, viewModel must have a defined setter for these properties.

Android data binding not shown

I am trying to use data binding in my app, but nothing is shown.
This is what I did:
I created an New Project with an Empty Activity.
I added
dataBinding {
enabled = true
}
to my build.gradle
This is my activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="game" type="my.name.bar.Bar"/>
</data>
<android.support.constraint.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="my.name.bar.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{game.GetFoo()}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</layout>
And this is my Bar class
public class Bar {
private String str;
public Bar() {
str = "Foo";
}
public String GetFoo() {
return str;
}
}
But I am only getting a white screen. If I replace the binding with just "Hello World!" then everything works fine. What am I doing wrong?
(promoted from the comment)
You must bind the value. In your case, it is something like this:
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setGame(new Bar());

How to use method of object in Android data binding?

Suppose I have this object:
public class Field
{
List<String> list;
public Field()
{
list = new ArrayList();
}
public boolean isOnTheList(String someText)
{
return list.contains(someText);
}
}
Now I want to use this function on a xml with binding like this.
<?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">
<data>
<import type="android.view.View"/>
<variable
name="field"
type="com.greendao.db.Field"/>
<variable
name="user"
type="com.package.User"/>
</data>
<LinearLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="#{field.isOnTheList(user.name)?View.VISIBLE:View.GONE}"
tools:context=".advisor.new_visit_report.activities.FieldsSelectionActivity"> ...
The problem is that is not working. Anyone has already tried this?
If everything else is set correctly, I would suggest to edit your method to return View.VISIBLE or View.GONE directly:
public int isOnTheList(String someText) {
return list.contains(someText) ? View.VISIBLE : View.GONE;
}
Used in xml:
android:visibility="#{field.isOnTheList(user.name)}

ViewDataBinding getVariable?

The 2 main questions are :
Why ViewDataBinding doesn't have a method like getVariable("variableName") that will look up for a variable and returns it or null if no variable with this name exists.
Is their any way/workaround to achieve this kind of behavior?
So to be more explicit : if I don't know the type of my ViewDataBinding, is their a way to get its variable or I must know its type?
Here is how it is working actually :
I havea layout called my_layout.xml :
<layout>
<data>
<variable
android:name="myVaribale"
android:type="String"/>
</variable>
</data>
<RelativeLayout
android:id="#+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="#{myVariable}"/>
</RelativeLayout>
<layout>
I inflate an instance of its ViewDataBinding :
MyLayoutBinding binding = (MyLayoutBinding) DataBindingUtil.inflate(inflater, R.layout.my_layout, root, false);
I can get its variable by calling the appropriate method :
String myVariable = binding.getMyVariable();
So this was how to get a variable when we know the type of the ViewDataBinding.
My problem is here :
Let's imagine I have 3 layouts called my_layout_1, my_layout_2, my_layout_3 and those 3 layouts are surrounded by a <layout> tag.
Those 3 layouts has also the same variable (myVariable).
So here are the layouts :
my_layout_1
<layout>
<data>
<variable
android:name="myVariable"
android:type="String"/>
</variable>
</data>
<RelativeLayout
android:id="#+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="#{myVariable}"
style="#style/my_style_1"/>
</RelativeLayout>
<layout>
my_layout_2
<layout>
<data>
<variable
android:name="myVariable"
android:type="String"/>
</variable>
</data>
<RelativeLayout
android:id="#+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="#{myVariable}"
style="#style/my_style_2"/>
</RelativeLayout>
<layout>
my_layout_3
<layout>
<data>
<variable
android:name="myVariable"
android:type="String"/>
</variable>
</data>
<RelativeLayout
android:id="#+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="#{myVariable}"
style="#style/my_style_3"/>
</RelativeLayout>
<layout>
So the different layout represent a text with a different style (I know it can be achieved by others way but the goal is just to explain why I need this function getVariable(variableName).
Imagine now that I got a layout called my_text_container which will randomly contain one of the 3 layouts.
my_text_container
<layout>
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<layout>
So I'll add a text by doing something like this (again, it's just for demonstration purpose) :
MyTextContainerBinding textContainerBinding = (MyTextContainerBinding) DataBindingUtil.inflate(inflater, R.layout.my_text_container, root, false);
int textLayoutRes;
int randomNumber = generateNumberBetween0and2();
switch(randomNumber) {
case 0: textLayoutRes = R.layout.my_layout_1;
break;
case 1: textLayoutRes = R.layout.my_layout_2;
break;
case 2: textLayoutRes = R.layout.my_layout_3;
break;
}
textContainerBinding.getRoot().addView(DataBindingUtil.inflate(inflater, textLayoutRes, root, false));
And finally I want to retrieve myVariable but I don't know if it's a layout 1, 2 or 3. Basically what could be done now is to use instanceof operator to check whether its a type MyLayoutBinding1, MyLayoutBinding2 or MylayoutBinding3. But as I said this use-case is only for demonstration purpose and I could have 999 different layouts.
So what I would like to do is :
ViewDataBinding myLayout = DataBindingUtil.getBinding(textContainerBinding.getRoot().getChildAt(0));
String myVariable = myLayout.getVariable("myVariable");
if(myVariable != null)
Log.d(TAG, "myLayout was MylayoutBinding1 or myLayoutBinding2 or myLayoutBinding3");
else
Log.d(TAG, "mylayout was not one of the 3 layouts");
Sorry for this (very) long post but thank's for reading it and for any future answers !
I am not sure if I get it but what I do is I declare a variable in the layout like this:
<data>
<variable
name="variableName"
type="bla.bla.VariableType"/>
</data>
Then first you get your layout binding in onCreate:
binding = DataBindingUtil.inflate(inflater, R.layout.your_layout, container, false);
Then you should send a variable to the layout in code like:
binding.setVariableName(yourVariable);
Then you can retrieve it like:
binding.getVariableName();
why ViewDataBinding Doesn't have getMethodVariable?
consider the normal scenario without binding. you have a text container layout. how will you include another layout inside it in a normal activity.
my_text_container.xml:(Normal activity)
You inflate this layout to your java file using R.layout.my_text_container, you won't inflate every layout to a different view to access textview inside it. just one inflate and go with it.
So the same procedure is followed in DataBinding as well, when you use include tag ,the respective fields will be inside MyTextContainerLayoutBinding.
you don't have to inflate it again and again with activity name like MyLayout1Binding, MyLayout2Binding. that's why getting variable name become unnecessary over here.
I think adding variability to Binding , will be more helpful in a place where you just want to display data. Data from one model across multiple included layouts,more helpful with Listviews,Recyclerviews(where layout use data from models).
you can't provide different type for different layouts ,if you are going include one layout to another.(Remember that this binds both layout to single name (parent_activity in your case container)).
Eg:
UserProfileModel:
public class UserProfileModel {
String firstname;
String lastname;
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
}
my_layout_1.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">
<data>
<variable name="user"
type="com.hourglass.lingaraj.bindingusingvariables.UserProfileModel" />
</data>
<LinearLayout
android:orientation="vertical"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:visibility="visible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{user.firstname}"
style="#style/mystyle_1"/>
<include layout ="#layout/my_layout_2"
app:user="#{user}" />
</LinearLayout>
</layout>
my_layout_2.xml:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="com.hourglass.lingaraj.bindingusingvariables.UserProfileModel"/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:visibility="visible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{user.lastname}"
style="#style/mystyle_2"/>
</RelativeLayout>
</layout>
MainActivity.java:
public class MainActivity extends AppCompatActivity {
MyLayout1Binding layout_binding;
UserProfileModel data_model;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout_1);
data_model = new UserProfileModel();
data_model.setFirstname("Lingaraj");
data_model.setLastname("Sankaravelu");
layout_binding = DataBindingUtil.inflate(getLayoutInflater(),R.layout.my_layout_1,null,false);
layout_binding = DataBindingUtil.setContentView(this,R.layout.my_layout_1);
layout_binding.setUser(data_model);
}
}
As you see we are using only one model to populate data across included layout. So there is no need get Variable name to verify which model is loaded as it's Binded to single layout.
There is no workaround to achieve this, us of I have tried.
So my answer will be No you can't get a variable name from binding
References.
No More findViewById
Android Data Binding: That Thing
Android Data Binding: Adding some variability
Android Data Binding: Express Yourself

view tag isn't correct on view:null

I'm using android data bindings and also using Dragger the problem is when I do this
MyLayoutbinding = DataBindingUtil.setContentView(this, R.layout.my_Layout);
I got the error
Caused by: java.lang.RuntimeException: view tag isn't correct on view:null
at com.rkmax.myapp.databinding.MyLayoutBinding.bind(MyLayoutBinding.java:191)
at android.databinding.DataBinderMapper.getDataBinder(DataBinderMapper.java:15)
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.rkmax.myapp.MyActivity.onCreate(MyActivity.java:26)
my_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.graphics.drawable.Drawable" />
<variable name="indicatorBg" type="Drawable" />
<variable name="categoryName" type="String" />
<variable name="progress" type="int" />
</data>
<RelativeLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/bg_blackboard">
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="15.3dp"
android:id="#+id/progressBar2"
android:max="10"
android:progress="#{progress}" />
</RelativeLayout>
</layout>
After a lot of trial and error what I did was copy the DraggerActivity source to and create my own DraggerActivity then add the following methods
private void configViews(View root) {
this.draggerPanel.addViewOnDrag(root);
if(this.shadowResID == -1) {
this.shadowResID = com.github.ppamorim.dragger.R.layout.layout_shadow;
}
this.draggerPanel.addViewOnShadow(this.inflateLayout(this.shadowResID));
super.setContentView(this.draggerPanel);
}
public void setContentView(View root) {
this.configDraggerView();
this.configViews(root);
super.setContentView(this.draggerPanel);
}
then on the onCreate method
View rootView = getLayoutInflater().inflate(R.layout.my_Layout, null, false);
mBinding = DataBindingUtil.bind(rootView);
setContentView(rootView);
in that way I get enable data bindings to my DraggerActivity

Categories

Resources