简体   繁体   中英

The android data binding is not working properly

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 clicking save( ), I found that the binding does not work, that is, the senhaConfirm into AmanteEditModel is null yet. Can anyone help me?

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.

TextWatcher Reference

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM