26

I have this object

ObservableInt someNumber;

public ObservableInt getSomeNumber()
{
    return someNumber;
}

public void setSomeNumber(ObservableInt number)
{
    this.someNumber = number;
}

and my AppCompatEditText is like this in xml code:

<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="@={String.valueOf(myObject.someNumber)}"
        android:gravity="center_horizontal"/>

I'm having this error:

Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
java.lang.RuntimeException: failure, see logs for details.
cannot generate view binders java.lang.NullPointerException
at android.databinding.tool.expr.MethodCallExpr.generateCode(MethodCallExpr.java:69)
at android.databinding.tool.expr.Expr.toFullCode(Expr.java:745)
at android.databinding.tool.expr.Expr.assertIsInvertible(Expr.java:767)
at android.databinding.tool.BindingTarget.addInverseBinding(BindingTarget.java:68)
at android.databinding.tool.LayoutBinder.<init>(LayoutBinder.java:228)
at android.databinding.tool.DataBinder.<init>(DataBinder.java:52)
at android.databinding.tool.CompilerChef.ensureDataBinder(CompilerChef.java:83)
at android.databinding.tool.CompilerChef.sealModels(CompilerChef.java:168)
at android.databinding.annotationprocessor.ProcessExpressions.writeResourceBundle(ProcessExpressions.java:149)
at android.databinding.annotationprocessor.ProcessExpressions.onHandleStep(ProcessExpressions.java:82)
at android.databinding.annotationprocessor.ProcessDataBinding$ProcessingStep.runStep(ProcessDataBinding.java:154)
at android.databinding.annotationprocessor.ProcessDataBinding$ProcessingStep.access$000(ProcessDataBinding.java:139)
at android.databinding.annotationprocessor.ProcessDataBinding.process(ProcessDataBinding.java:66)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91)
at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176)
at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856)
at com.sun.tools.javac.main.Main.compile(Main.java:523)
at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)
at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)
at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:46)
at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:33)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:104)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:53)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:38)
at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:35)
at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:25)
at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:163)
at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:145)
at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:93)
at com.android.build.gradle.tasks.factory.AndroidJavaCompile.compile(AndroidJavaCompile.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:75)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$IncrementalTaskAction.doExecute(AnnotationProcessingTaskFactory.java:245)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:221)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$IncrementalTaskAction.execute(AnnotationProcessingTaskFactory.java:232)
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:210)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:66)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:203)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:185)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:66)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:50)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:25)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:110)
at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
at org.gradle.initialization.DefaultGradleLauncher$4.run(DefaultGradleLauncher.java:153)
at org.gradle.internal.Factories$1.create(Factories.java:22)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:53)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:150)
at org.gradle.initialization.DefaultGradleLauncher.access$200(DefaultGradleLauncher.java:32)
at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:98)
at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:92)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:63)
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:92)
at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:83)
at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:99)
at org.gradle.tooling.internal.provider.runner.BuildModelActionRunner.run(BuildModelActionRunner.java:46)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.tooling.internal.provider.runner.SubscribableBuildActionRunner.run(SubscribableBuildActionRunner.java:58)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:48)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:30)
at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:81)
at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:46)
at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:52)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
at org.gradle.util.Swapper.swap(Swapper.java:38)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.health.DaemonHealthTracker.execute(DaemonHealthTracker.java:47)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.health.HintGCAfterBuild.execute(HintGCAfterBuild.java:41)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:237)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

I already have tried just with

android:text="@={myObject.someNumber}"

but I'm having this error:

Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
java.lang.RuntimeException: Found data binding errors.
****/ data binding error ****msg:Cannot find the getter for attribute     'android:text' with value type int on android.support.v7.widget.AppCompatEditText.
file:C:\Users\Moviit\AndroidStudioProjects\pbbchile-android\app\src\main\res\layout\row_agro_tab.xml
loc:51:8 - 60:48
****\ data binding error ****

Anybody has an example of how to do this?

serv-inc
  • 35,772
  • 9
  • 166
  • 188
Dan Ponce
  • 636
  • 1
  • 8
  • 24
  • 2
    Your first expression will not work, as there is no reverse expression. Your second expression will not work, as Android will treat it as a string resource. My guess is that you will need to switch your view model to use `ObservableField` instead of `ObservableInt`. – CommonsWare Aug 16 '16 at 19:22

6 Answers6

22

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

variable is string type

<android.support.v7.widget.AppCompatEditText
    ...
    android:text="@={model.someString}"
    />

variable is number

<android.support.v7.widget.AppCompatEditText
    ...
    android:text="@={`` + model.someNumber}"
    />

`` two back apostrophe do binding automatically

  • convert number to string when setting it on EditText
  • convert string text to number when setting in Model

Tip

From documentation you can see, two-way binding can be used for many purpose.

  1. CheckBox, RadioButton, Switch, ToggleButton

android:checked="@={model.checked}"

  1. RadioGroup - android:checkedButton

android:checkedButton="@={model.selectedId}"

  1. RatingBar - android:rating

android:rating="@={model.rating}"

etc.

Khemraj Sharma
  • 57,232
  • 27
  • 203
  • 212
  • Can you help me with this: https://stackoverflow.com/questions/64596538/android-two-way-databinding-problem-of-ternary-operator-must-be-constant Thank you. – Sam Chen Oct 29 '20 at 18:10
14

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.

George Mount
  • 20,708
  • 2
  • 73
  • 61
  • 1
    It throws this error: Error:Execution failed for task ':app:compileDebugJavaWithJavac'. > java.lang.RuntimeException: Found data binding errors. ****/ data binding error ****msg:The expression ("") + (dosisAgrochemical) cannot cannot be inverted: String concatenation operator (+) is not supported in two-way binding. file:C:\Users\Moviit\AndroidStudioProjects\pbbchile-android\app\src\main\res\layout\item_agro_dosis.xml loc:23:29 - 23:51 ****\ data binding error **** – Dan Ponce Aug 23 '16 at 17:43
  • Sorry, it must not be released in 2.2. I guess it will have to wait for 2.3. – George Mount Aug 24 '16 at 00:05
  • 2
    It wont allow clearing all value and entering new. Retains last digit – Tejasvi Hegde Dec 18 '19 at 11:15
  • Can you help me with this: https://stackoverflow.com/questions/64596538/android-two-way-databinding-problem-of-ternary-operator-must-be-constant Thank you. – Sam Chen Oct 29 '20 at 18:11
5

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.

Dan Ponce
  • 636
  • 1
  • 8
  • 24
  • Will the InverseBindingAdapter affect other bindings which require the binding to String? – gopalanrc Oct 15 '17 at 07:06
  • Yes @gopalanrc, every time you have in the "android:text" tag something like "@={myObject.someNumber}" the binding and inverse binding adapters will work – Dan Ponce Oct 16 '17 at 14:09
  • @DanPonce in this answer there are two problems: 1) if you set a Observable variable ( android:text = "@{Observable}" ) then bindIntegerInText will be inserted into the infinite loop so you should check if new Variable is different form new variable. (reference : https://developer.android.com/topic/libraries/data-binding/two-way#two-way-custom-attrs) 2) if you want to modify the text for example in middle of the string ("abc(here)dfgh") when you start to write new character in the middle the cursor will moved to the end of string – Fidan Bacaj Feb 04 '21 at 11:00
3

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>
Community
  • 1
  • 1
Long Ranger
  • 5,888
  • 8
  • 43
  • 72
  • Thanks a lot for your solution but it's giving me an error. The EditText starts in 0 value but when you erase it, the error: Invalid int: "" because of the BindingAdapter trying to parse a "" value. Do you have a solution for this? – Dan Ponce Sep 16 '16 at 16:03
2

@CommonsWare is right, you should use ObservableField<Str‌​ing> instead of ObservableInt. If you really needit as number, just parse it Integer.valueOf(stringNumber).

public ObservableField<Str‌​ing> 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;
    }
}
Roman_D
  • 4,680
  • 2
  • 14
  • 17
1

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);
}
Andrii Kovalchuk
  • 4,351
  • 2
  • 36
  • 31
  • What I'm trying to do is using a ObservableInt with two way binding on my EditText. I don't have problems with strings – Dan Ponce Nov 14 '16 at 14:10