*BindingImpl class : cannot inherit from final *Binding - android

I got this error in the generated BindingImpl class but the binding class is not final, it is abstract...
BindingImpl class :
public class FragmentImageBindingImpl extends FragmentImageBinding implements com.example.memoriserlesnombres.generated.callback.OnClickListener.Listener {
...
}
Binding class:
public abstract class FragmentImageBinding extends ViewDataBinding {
...
}
Any ideas ?
I already try to clean/rebuilt project, invalidate caches/restart and reinstall android studio without success. I saw another post saying to delete plugin files but they don't exist.
I'm new to android, but it seems very buggy to me :/
EDIT :
I still have the error (in the class) but my app works fine, so I think I can ignore it, this is just an Android Studio issue.
Here is the 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="view"
type="com.example.memoriserlesnombres.image.ImageViewModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".image.ImageFragment">
<TextView
android:id="#+id/current_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{Integer.toString(view.currentNumber)}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/current_number">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/associated_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/hint"
android:text="#={view.image}" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
android:contentDescription="#string/save_image"
android:onClick="#{() -> view.saveImage()}"
app:srcCompat="#drawable/ic_done_black_24dp" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

In one of your layout xml files, remove the <layout> tag and add it back.
This solved a similar issue in my project.

I had this error because I had multiple xml files for the same layout (e.g fragment_xxx, fragment_xxx_land, fragment_xxx_sw600dp etc.) changed one layout and forgot to update the other ones. So if you have multiple layouts, make sure that all have the same tags / are similar.

Also clean project and rebuild worked for me!

its because your viewmodel package is not same as the one it is in. like
the viewmodel class is laying somewhere else while the package inside the viewmodel class is pointing to somewhere else so please make it same as the location of viewmodel inside your viewmodel class
inshort recheck if your ImageViewModel is lying in same place as this one com.example.memoriserlesnombres.image.ImageViewModel
if the location is different from the package then change the package inside the ImageViewModel class to the location this class is in...
also change the ImageViewModel location in xml file too... and you are good to go...
this error sometime i mean very rarly arise when you copy a class from one package to another package inside the class...

Related

Android string link not working with databinding

I am trying to use Databinding in combination with a XML String which has some links and a variable. The problem is that the links do not work anymore, when Databinding is used.
XML text
<data>
<variable
name="vm"
type="com.example.app.framework.ui.viewmodel.EmailViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/app_standard_agb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:linksClickable="true"
android:text="#{#string/app_agb(vm.btnText)}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</TextView>
</androidx.constraintlayout.widget.ConstraintLayout>
When I use android:text="#{#string/app_agb.concat(vm.btnText)}" I get a NullPointer Exception which is impossible because I use the variable somewhere else and it is 1000% not null. Just using android:text="#string/app_agb" works.
String
<string name="app_agb">
By clicking %1$s you accept the
privacy policies and
agbs from example..
</string>
Code in Fragment
app_standard_agb.movementMethod = LinkMovementMethod.getInstance()
EDIT
Does it make any difference that I include my app_standard_agb in my layout?
i think this is because of the LiveData doesn't emit Data until it get Observed, so the value of it is null before it get Observed, you can use #BindingAdapter and check if the value is not null like following code
put code bellow somewhere in your project(I've tried just in Kotlin):
#BindingAdapter("android:bindLink")
fun bindLink(view: TextView, link: String?) {
link?.let{
view.text = view.context.getString(R.string.app_agb, it)
}
}
and the XML should be like this:
<TextView
android:id="#+id/app_standard_agb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:linksClickable="true"
android:bindLink="#{vm.btnText}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

Android: Pass different content from viewmodel to different include-tags

In my task app I want to use databinding for the task overview. I've grouped tasks in three categories: overdue, today and future.
My task_overview.xml defines the following viewmodel (which contains three arraylists with the different tasks)
<data>
<variable
name="viewModel"
type="de.taskapp.ui.taskOverview.viewmodel.TaskOverviewViewModel" />
</data>
A few steps later I include the layout for the three task lists with the include tag like this
<include layout="#layout/layout_task_list"
android:id="#+id/overdued_tasks_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/headline"/>
<include layout="#layout/layout_task_list"
android:id="#+id/todays_tasks_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/overdued_tasks_list"/>
<include layout="#layout/layout_task_list"
android:id="#+id/future_tasks_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/todays_tasks_list"/>
It would be awesome if I could do something like this to pass the different lists from the viewmodel to the layout_task_list.xml via the include tag
app:entries="#{viewModel.todaysTasks}" // for the todays task list case
My layout_task_list.xml looks like this
<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="tasks"
type="android.databinding.ObservableArrayList" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.AppCompatTextView
android:id="#+id/subheading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/SubheadlineWithBackground"
tools:text="Heute"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/task_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/spacing_large"
android:layout_marginRight="#dimen/spacing_large"
android:nestedScrollingEnabled="false"
app:entries="#{tasks}" //recyclerviewbinding is already there
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
app:layout_constraintTop_toBottomOf="#id/subheading"/>
</android.support.constraint.ConstraintLayout>
As you may suggest...the code is not working. This error message is shown
data binding error ****msg:Cannot find the setter for attribute 'app:entries' with parameter type android.databinding.ObservableList<de.taskapp.data.entity.Task> on de.molske.einfachmachen.databinding.LayoutTaskListBinding. file:/Users/app/src/main/res/layout/layout_task_overview.xml loc:38:40 - 38:60 ****\ data binding error ****
Okay yeah its telling me that he cannot find the setter for app:entries...but isn't there a "beautiful" way to pass the three lists to the three include-layouts? I don't like the idea to copy and paste the same layout three times just to be able to pass the different lists.
Thanks in advance.
(ps.: I know that there is the possibility to solve this by java / android code but I would like to know if there is a databind way to do this ;-)
Okay, classic me. After a few more googling I found the solution. Adding the next lines to the data-section of the included file everything works fine!
<import type="java.util.List"/>
<import type="de.molske.einfachmachen.data.entity.Task"/>
<variable name="title" type="java.lang.String"/>
<variable
name="tasks"
type="List<Task>"/>
It seems that it's important to define the exact type of the tasks variable. Because its type is a genereic < and > instead of < and > for defining the type.

Android DataBinding & MVVM - Using same name for layout files in different layout folders

I've been developing an app with data binding & MVVM.
I'm trying to use an alternative layout for my app on landscape mode. I have:
layout/fragment_content.xml
layout-land/fragment_content.xml
Both layouts have same views with different look, and get feeds from same view models, like this:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data class="MyBinding">
<variable
name="viewModel"
type="com.myapp.package.viewModel.VMFirst"/>
<variable
name="controlModel"
type="com.myapp.package.viewModel.VMSecond"/>
</data>
<DIFFERENT CONTENT HERE>
All the views and id's exist in both layouts.
Well, problem is, it doesn't compile, error is simply "cannot find symbol method getViewModel" and getter for the other variable.
What I tried so far:
Using layout and layout-land folders ( Failed, error is explained above )
Using layout aliases Use Layout Aliases which I found here Issue 199344: Data binding does not work with layout aliases. I didn't change anything in xml files while trying this approach. This also failed, error is Could not write to com.myapp.package.databinding.MyBinding
Is it not possible to use data binding data tag in multiple layout files ? What should I use to use different layouts for different states while using data binding ? Thanks !
Edit: deleting class="MyBinding" did not change errors.
If anyone searches for this question, after 2 years I tried to do the same, and I saw it's working all fine now.
I created a layout file activity_main under layout and layout_sw600dp. Here's the layout under layout resources:
<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">
<variable
name="small_variable"
type="Integer"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/myRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<View
android:id="#+id/small_square"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#android:color/holo_blue_bright"
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>
This one is the layout under layout_sw600dp folder:
<?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">
<variable
name="big_variable"
type="Long"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/myRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<View
android:id="#+id/big_square"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#android:color/holo_blue_bright"
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>
Both has a view but it has different id in each: small_square and big_square.
I run the project on phone & tablet. Here are my findings:
DataBinding creates an implementation that contains ALL views and variables under all layout files of same name in different layout folders.
Views that exists in all layouts are not nullable, all others are nullable. In above XML's, myRoot is not a nullable view when using binding from Kotlin, while big_square and small_square are nullable views. Variables are nullable whether or not they exists in all layouts ( which is expected behaviour ).
You cannot name binding classes different in each file. It has to be same ( MainBinding in above examples, or if you don't define it LayoutResourceName + Binding by default ).
Names for views and variables on binding implementation are camel case. So my small_variable & small_square was binding.smallVariable and binding.smallSquare on code side.
With Kotlin, you can just use views like binding.bigSquare?.operation, which is great that you don't need to check if it's tablet or phone or view is null or not beforehand.
Just a tip, you can assign binding fields even if layout that they are in won't be used. You can still say binding.smallVariable = 3 on code and it'll do the assignment and save the value. I think it's good to be careful.
I heavily use MVVM in my apps and am also building a library around it.
I follow the convention that there is a single ViewModel in every XML. Also, the name of the viewmodel variable is same in all XMLs.
So, in your case, you can create another ViewModel class that contains VMFirst and VMSecond.
public class ParentVM {
VMFirst first;
VMSecond second;
}
Both the XMLs (portrait and landscape) will have same names, say activity_main.xml.
<layout>
<data>
<variable
type="ParentViewModel"
name="vm"/>
</data>
Then no check is required in MainActivity code.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewDataBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setVariable(BR.vm, new ParentViewModel());
}
This works.
Advantages of single ViewModel
In fact, because I follow same variable name throughout all xmls, I am able to include the binding logic in a base class MvvmActivity itself. So, all my activities look like:
public class MainActivity extends MvvmActivity {
#NonNull
#Override
protected ViewModel createViewModel() {
return new MainViewModel();
}
#Override
protected int getLayoutId() {
return R.layout.activity_main;
}
}
MvvmActivity implementation: MvvmActivity.java
Another advantage of keeping a constant data binding variable is that you can setup RecyclerView or ViewPager adapters in XML itself. See Setup RecyclerView from XML for more details.
By default, a Binding class will be generated based on the name of the layout file, converting it to Pascal case and suffixing "Binding" to it. The above layout file was main_activity.xml so the generate class was MainActivityBinding. --Binding Data
and generated at compile time.
so, select different layout by java code.
layout/
R.layout.activity_main
R.layout.activity_main_tablet
values/
<bool name="is_mobile">true</bool>
<bool name="is_tablet">false</bool>
values-w820dp/
<bool name="is_mobile">false</bool>
<bool name="is_tablet">true</bool>
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(getResources().getBoolean(R.bool.is_mobile)) {
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
} else {
ActivityMainTabletBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main_tablet);
}
}

Android dataBinding - #BindingAdapter custom app namespace being ignored

I have created a custom bindingAdapter in android and when i pass in the color i want the color to change, this is actually for a test im working on just to make sure it works. Here is the code:
here is my view Model for the data binding:
public class User {
public ObservableInt visible;
public User(int visible) {
this.visible=new ObservableInt(visible);
}
#BindingAdapter({"app:bindColor"}) //notice the bindColor custom attribute
public static void setTextColor(TextView view,String color) {
if("green".equals(color))
view.setTextColor(Color.parseColor("#63f421"));
}
}
Now in my xml file which is binded to this model im expected to pass in a color so that the setTextColor method can use it:
<?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 class="MainActivityBinder">
<variable name="user" type="com.example.android.floatingactionbuttonbasic.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tv_one"
android:text="my first textview"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tv_two"
android:text="my second textview"
android:visibility="#{user.visible}"
app:bindColor="#{'green'}" //see im passing in the green string here
android:textColor="#android:color/holo_green_dark"/>
</LinearLayout>
</layout>
I am getting the error at runtime time of:
Error:(27, 65) error: package com.example.android.floatingactionbuttonbasic.databinding does not exist
Warning:Application namespace for attribute app:bindColor will be ignored.
Error:(24, 33) Identifiers must have user defined types from the XML file. een is missing it
Error:Execution failed for task ':Application:compileDebugJavaWithJavac'.
> java.lang.RuntimeException: Found data binding errors.
if i take out the bindingAdapter stuff it works perfectly with the other databinding stuff. Its just this custom binding thats not working. My project is titled floatingactionbuttonbasic btw.
I was able to get this to work. The issue was how i was passing in the string. It should have the `` around it.
app:bindColor="#{`green`}"
you can also do this :
app:bindColor='#{"green"}'
But what seems to not be allowed is this notation:
app:bindColor="#{'green'}"
i wrote a blog about it to help others if interested.

Android data Binding - ObservableArrayMap how to implement in a POJO

From the observable objects section of the android blog on data binding
The POJO class should extend BaseObservable unless your using ObservableFields. Let's look at my current POJO which is very simple and just stores an observableInt:
public class User {
public ObservableInt visible;
public User(int visible) {
this.visible=new ObservableInt(visible);
}
}
I want to add an Observable Collection to this pojo but im not clear how to layout the xml if i do that. How would i call it. Lets say i want to add the current arraymap to my POJO:
ObservableArrayMap<String, Object> myCollection = new ObservableArrayMap<>();
myCollection.put("firstName", "Google");
myCollection.put("lastName", "Inc.");
myCollection.put("age", 17);
How do i incorporate this into my xml for data binding. My xml file is simple and looks like this:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.android.floatingactionbuttonbasic.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="my first textview"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="my second textview"
android:visibility="#{user.visible}"/>
</LinearLayout>
</layout>
I am confused how i would add variables for ObservableArrayMap into this xml file and be able to use it. Can someone help ?I feel i can pass it into the User POJO fine, its just from xml i dont know how i'd reference it? The reason im confused is because the ObservableArrayMap is going to be a attribute of the User class, how do i access it since its going to be a member of the User class ?
You can access the map values like any other public observable from your xml.
For example:
public class Model{
public ObservableArrayMap<Integer,String> MyMap=new ObservableArrayMap<>();
public Model(){
MyMap.put(1,"easy");
}
}
Access the value from your xml:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="model"
type="de.example.models.Model"/>
</data>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="#dimen/padding"
android:text="#{model.MyMap.get(1)}"/>
</layout>

Categories

Resources