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">
Related
I want to set text using binding adapter.Here is the MyBindingAdapter.kt
#BindingAdapter("android:setTitle")
fun setTitle(textView : TextView,text: String){
textView.text = text
}
in activity_table.xml I used setTitle like this
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_column="1"
android:layout_weight="1"
android:gravity="center"
android:setTitle="Hello word"/>
and I getting below error in compile time
You need to change from #BindingAdapter("android:setTitle") to #BindingAdapter("setTitle") in your MyBindingAdapter.kt.
Also you need to change in xml file from android:setTitle="Hello word" to setTitle="Hello word"
It should work now!
Android studio will not consider #BindingAdapter("android:setTitle") while binding it, you need to write only #BindingAdapter("setTitle") to execute it perfectly, otherwise it will give that binding error while compile time.
First make sure you have to enclose you layout within the <layout> tag
<layout
xmlns:android="http://schemas.android.com/apk/res/android">
..... </layout>
and #BindingAdapter("android:setTitle") change as #BindingAdapter("title")
it should work.
I am using databinding library. I have a layout which have some edittext for getting basic user input like name, email, password etc. I want to validate these inputs inside the viewmodel on button click. I am a bit confused how to access edittext input on button click inside the view model.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="ViewModel"
type="me.example.model.LoginViewModel"/>
<EditText
android:id="#+id/name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="13sp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Submit"
android:onClick="#{() -> ViewModel.onSubmitClick()}"/>
</layout>
this is the button click method in the view model
fun onSubmitClick(){
Log.e("Clicked ", "True")
}
}
You can reference the EditText within the Button's binding expression:
android:onClick="#{() -> ViewModel.onSubmitClick(name.getText().toString())}"
One caveat is that snake casing becomes camel casing when doing this, so if your View's android:id is name_edit_text, you would use nameEditText.getText() within the binding expression.
Clicking the Button will then call this method in the ViewModel:
fun onSubmitClick(editTextString: String) {
Log.d("LOG", editTextString)
}
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...
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.
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.