The android data binding is not working properly
EDIT: According to Remi David Android Studio now features two way databinding. The solution I describe below should no longer be nessesary.
Thanks Remi for pointing that out.
With respect to user input Android Databinding is only one way. The GUI will automagically reflect any changes in the model, but not vice versa.
You need to add a TextChangeListener to your model class which sets the model property when the user changes anything.
Example:
public class AmanteEditModel extends BaseObservable {
private String senhaConfirm;
@Bindable
public String getSenhaConfirm() {
return senhaConfirm;
}
public void setSenhaConfirm(String senhaConfirm) {
this.senhaConfirm = senhaConfirm;
notifyPropertyChanged(BR.senhaConfirm);
}
// Textwatcher Reference: http://developer.android.com/reference/android/text/TextWatcher.html
public TextWatcher getMyEditTextWatcher() {
return new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
public void onTextChanged(CharSequence s, int start,
int before, int count) {
// Important! Use the property setter, otherwhise the model won't be informed about the change.
setSenhaConfirm(s);
}
};
}
}
In your layout xml change EditText to this:
<EditText
android:id="@+id/amante_edit_senha_confirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:hint="Confirme a senha"
android:inputType="textPassword"
android:maxLines="1"
android:text="@{model.senhaConfirm}"
app:addTextChangeListener="@{model.myEditTextWatcher}"
/>
Watch for the namespace of addTextChangeListener. This method might not be available through the android: namespace, so I'm using app: here. You may also use bind: to make the binding more clear.
So don't miss to add
xmlns:app="http://schemas.android.com/apk/res-auto"
or
xmlns:bind="http://schemas.android.com/apk/res-auto"
to your XML namespaces.
This solution works for all input controls, custom included, given you provide the correct Listeners in your model.
araraujo
Updated on June 24, 2022Comments
-
araraujo about 2 years
I would like to help to fix a problem.
First, following the details of my code:
build.gradle (Project: android) buildscript { repositories { jcenter() mavenCentral() maven { url '/home/melti/java/repository' } } dependencies { classpath "com.android.tools.build:gradle:1.3.0-beta4" classpath "com.android.databinding:dataBinder:1.0-rc0" } } allprojects { repositories { jcenter() mavenCentral() maven { url '/home/melti/java/repository' } } }
build.gradle (Module: app)
apply plugin: 'com.android.application' apply plugin: 'com.android.databinding' android { compileSdkVersion 22 buildToolsVersion "23.0.0 rc2" defaultConfig { applicationId "br.com.soma" minSdkVersion 16 targetSdkVersion 21 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.0.0' compile 'com.android.support:recyclerview-v7:21.0.3' compile 'com.android.support:cardview-v7:21.0.3' compile 'com.squareup.picasso:picasso:2.5.2' compile 'com.squareup.okhttp:okhttp:2.4.0' compile 'com.google.code.gson:gson:2.3.1' compile 'org.springframework:spring-core:4.1.7.RELEASE' compile 'org.apache.commons:commons-io:1.3.2' }
AmanteEditModel
package br.com.soma.amante.edit; import android.databinding.BaseObservable; import android.databinding.Bindable; import br.com.soma.BR; /** * Created by spassu on 09/07/15. */ public class AmanteEditModel extends BaseObservable { private String senhaConfirm; @Bindable public String getSenhaConfirm() { return senhaConfirm; } public void setSenhaConfirm(String senhaConfirm) { this.senhaConfirm = senhaConfirm; notifyPropertyChanged(BR.senhaConfirm); } }
fragment_amante_edit
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto"> <data> <variable name="model" type="br.com.soma.amante.edit.AmanteEditModel"/> </data> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" > <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" style="@style/card_edit_style" android:layout_gravity="top" card_view:cardCornerRadius="0dp"> <EditText android:id="@+id/amante_edit_senha_confirm" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:hint="Confirme a senha" android:inputType="textPassword" android:maxLines="1" android:text="@{model.senhaConfirm}" /> </android.support.v7.widget.CardView> </ScrollView> </layout>
AmanteEditFragment
package br.com.soma.amante.edit; import android.app.Fragment; import android.databinding.DataBindingUtil; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import br.com.soma.R; import br.com.soma.amante.view.AmanteViewActivity; import br.com.soma.databinding.FragmentAmanteEditBinding; /** * Created by spassu on 27/05/15. */ public class AmanteEditFragment extends Fragment { private AmanteEditModel model; private static final String AMANTE_ID = "amanteId"; public static final String DEFAULT_FRAGMENT_TAG = "amanteEditFragment"; // Views private long amanteId; public AmanteEditFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { model = new AmanteEditModel(); FragmentAmanteEditBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_amante_edit, container, false); binding.setModel(model); return binding.getRoot(); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.menu_amante_edit, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()) { // The Save button was pressed case R.id.menu_amante_edit_save: save(); getActivity().finish(); return true; } return super.onOptionsItemSelected(item); } public static AmanteEditFragment newInstance(long id) { AmanteEditFragment fragment = new AmanteEditFragment(); Bundle args = new Bundle(); args.putLong(AmanteViewActivity.EXTRA_AMANTEID, id); fragment.setArguments(args); return fragment; } private void save() { Toast.makeText(getActivity(), model.getSenhaConfirm(), Toast.LENGTH_SHORT).show(); } }
After enter data in
senhaConfirm
and clickingsave(
), I found that the binding does not work, that is, thesenhaConfirm
intoAmanteEditModel
is null yet. Can anyone help me?