I have this object
ObservableInt someNumber;
public ObservableInt getSomeNumber()
{
return someNumber;
}
public void setSomeNumber(ObservableInt numbe
There is an unpublished trick for simple primitive conversions:
<android.support.v7.widget.AppCompatEditText
android:layout_width="0dp"
android:layout_height="@dimen/agro_item_height"
android:layout_weight="1"
android:inputType="numberDecimal"
android:text="@={`` + myObject.someNumber}"
android:gravity="center_horizontal"/>
I believe it was only added in Android Studio 2.2.
Simply do this:
android:text="@={user.username}"
Full code:
<EditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="user name"
android:text="@={user.username}"/>
And User class
public class User {
public ObservableField<String> username = new ObservableField<>();
public ObservableField<String> password = new ObservableField<>();
public User() {
this("", "");
}
public User(String username, String password) {
this.username.set(username);
this.password.set(password);
}
Thanks to the binding adapters from @LongRanger I was able to advance a lot more in my solution but I had to make some changes on the adapters and in my code. First of all I had to init the ObservableInt member like this:
ObservableInt someNumber;
public ObservableInt getSomeNumber()
{
return someNumber;
}
public void setSomeNumber(ObservableInt number)
{
this.someNumber = number;
}
Second, I had to change the adapters given by @LongRanger to be like this:
@BindingAdapter("android:text")
public static void bindIntegerInText(AppCompatEditText tv, int value)
{
tv.setText(String.valueOf(value));
// Set the cursor to the end of the text
tv.setSelection(tv.getText().length());
}
@InverseBindingAdapter(attribute = "android:text")
public static int getIntegerFromBinding(TextView view)
{
String string = view.getText().toString();
return string.isEmpty() ? 0 : Integer.parseInt(string);
}
That way I avoid the error: Invalid int "", when trying to do Integer.parse(...) on the @InverseBindingAdapter. After this I had to put the cursor on the end of the EditText with the @BindingAdapter, otherwise the cursor kept moving to the start.
You can do two-way binding on EditText.
Using one-way data binding, you can set a value on an attribute and set a listener that reacts to a change in that attribute
<android.support.v7.widget.AppCompatEditText
...
android:text="@={model.someString}"
/>
<android.support.v7.widget.AppCompatEditText
...
android:text="@={`` + model.someNumber}"
/>
`` two back apostrophe do binding automatically
From documentation you can see, two-way binding can be used for many purpose.
android:checked="@={model.checked}"
android:checkedButton
android:checkedButton="@={model.selectedId}"
android:rating
android:rating="@={model.rating}"
etc.
I try to use the custom setter as @George Mount mentioned(https://medium.com/google-developers/android-data-binding-custom-setters-55a25a7aea47#.vsry4d95w) , and inspired by this answer (Android two way binding with Integer type causes databinding does not exist)
You can still use the original code for two-way binding.
Model class
public class Age {
private ObservableInt someNumber;
private ObservableField<String> someStr;
public Age() {
someNumber = new ObservableInt();
someStr = new ObservableField<>();
}
public ObservableInt getSomeNumber() {
return someNumber;
}
public void setSomeNumber(ObservableInt pSomeNumber) {
someNumber.set(pSomeNumber.get());
}
public ObservableField<String> getSomeStr() {
return someStr;
}
public void setSomeStr(ObservableField<String> pSomeStr) {
someStr.set(pSomeStr.get());
}
}
Custom setter and getter for the attribute
@BindingAdapter("android:text")
public static void bindIntegerInText(AppCompatEditText tv, int value) {
tv.setText(String.valueOf(value));
}
@InverseBindingAdapter(attribute = "android:text")
public static int getIntegerFromBinding(TextView view) {
return Integer.parseInt(view.getText().toString());
}
Code in Activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMain2Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_main2);
mAge = new Age();
mAge.setSomeNumber(new ObservableInt(3));
mAge.setSomeStr(new ObservableField<>("Test"));
binding.setAge(mAge);
binding.btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mAge.setSomeNumber(new ObservableInt(4));
mAge.setSomeStr(new ObservableField<>("Hello World"));
}
});
}
I make 4 demo with ObservableInt, Observable , normal String resource and binding String resource in the xml.
<string name="helloworld">Hello World</string>
activity_main3.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
>
<data>
<variable
name="age"
type="example.com.testerapplication.Age"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.AppCompatEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={age.someNumber}"/>
<android.support.v7.widget.AppCompatEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={age.someStr}"/>
<android.support.v7.widget.AppCompatEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/helloworld"/>
<android.support.v7.widget.AppCompatEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{@string/helloworld}"/>
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Test"
/>
</LinearLayout>
</layout>
@CommonsWare is right, you should use ObservableField<String>
instead of ObservableInt
. If you really needit as number, just parse it Integer.valueOf(stringNumber)
.
public ObservableField<String> someNumber;
//and in xml code:
<EditText
android:layout_width="0dp"
android:layout_height="@dimen/agro_item_height"
android:layout_weight="1"
android:inputType="numberDecimal"
android:text="@={myObject.someNumber}"
android:gravity="center_horizontal"/>
EDITED: Or, as mentioned, write custom @InverseBindingAdapter
public class MyEditTextBindingAdapters {
@BindingConversion
public static String intToStr(Integer value) {
return value != null ? String.valueOf(value) : "";
}
@InverseBindingAdapter(attribute = "android:text")
public static Integer captureIntValue(EditText view) {
long value = 0;
try {
value = Integer.parseInt(view.getText().toString());
} catch (NumberFormatException e) {
e.printStackTrace();
}
return value;
}
}