6

I searched a lot about observable models and parameters but I got confused!

1-some of model extend from BaseObservable and setnotifyChange(); in setters and bind them for example to edittext like this: app:addTextChangedListener="@{viewModel.getEmailTextWatcher}" and that notifyChange() update text by changing email parameter of user model.

2-and some of them use livedata for observing and change UI in onChanged() method. How can I use liveData and change UI by databinding? not by onChanged(). and when onChanged() use while we can use databinding for UI changes?

edited: here is my coded:

public class MainActivity extends AppCompatActivity implements LoginResultCallback {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    activityMainBinding.setViewModel(ViewModelProviders.of(this, new LoginViewModelFactory(this)).get(LoginViewModel.class));


}

@Override
public void onSuccess(String s) {
    Toasty.success(getApplicationContext(), s, Toast.LENGTH_SHORT).show();
}

@Override
public void onError(String s) {
    Toasty.error(getApplicationContext(), s, Toast.LENGTH_SHORT).show();
}
}

and here is interface:

public interface LoginResultCallback {
void onSuccess(String s);
void onError(String s);
}

and here is User model:

public class User {

@NonNull
public String mEmail;

public User(@NonNull final String email, @NonNull final String password) {
    mEmail = email;
}

@NonNull
public String getEmail() {
    return mEmail;
}

public void setEmail(@NonNull final String email) {
    mEmail = email;
}

}

here is ViewModel:

public class LoginViewModel extends ViewModel {
public MutableLiveData<User> user = new MutableLiveData<>();
;
private LoginResultCallback mDataListener;

LoginViewModel(@NonNull final LoginResultCallback loginDataListener) {
    mDataListener = loginDataListener;
    if (user != null) {
          //help me fill here
    }
}

public TextWatcher getEmailTextWatcher() {
    return new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        }

        @Override
        public void afterTextChanged(Editable editable) {
         //help me fill here
        }
    };
}
}

here is layout:

<?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>

    <variable
        name="viewModel"
        type="com......viewmodels.LoginViewModel" />

</data>


<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="8dp"
        android:orientation="vertical">

        <EditText
            android:id="@+id/test"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="test"
            android:padding="8dp"
            android:text="@{viewModel.user}" />

        <EditText
            android:id="@+id/inEmail"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Email"
            android:inputType="textEmailAddress"
            android:padding="8dp"
            app:addTextChangedListener="@{viewModel.getEmailTextWatcher}" />


        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:onClick="@{viewModel::onLoginClicked}"
            android:text="LOGIN" />


    </LinearLayout>

</ScrollView>

i just want to change inEmail edittext and upper edittext change by data binding

Reza Abedi
  • 419
  • 4
  • 16

1 Answers1

3

First, enable data binding in your app level build.gradle as follows:

android {
    ...
    dataBinding {
        enabled = true
    }
    ...
}

Make sure you have lifecycle dependencies as well:

dependencies {
    ... 
    implementation "android.arch.lifecycle:runtime:1.1.1"
    implementation "android.arch.lifecycle:extensions:1.1.1"
    annotationProcessor "android.arch.lifecycle:compiler:$versions.lifecycle:1.1.1"
    ...
}

Now, let's say you have some User class:

public class User {
    private String firstName;

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getFirstName() {
        return firstName;
    }
}

Then, you could have some UserLiveData:

public class UserLiveData extends LiveData<User> {
    public UserLiveData() {
        setValue(new User());
    }
} 

Here's a simple UserViewModel:

public class UserViewModel extends ViewModel {
    private UserLiveData liveData;

    public UserViewModel() {
        liveData = new UserLiveData();
    }

    public void observeLiveDate(LifecycleOwner owner,
                                  Observer<User> observer) {
        liveData.observe(owner, observer);
    }
}

Now, activity_main.xml defines layout with the user's first name EditText and Button:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="textPersonName"
        android:text="@={user.firstName}"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/load_button"
        android:text="Load"/>

</LinearLayout>

Please note @={user.firstName}. It's needed for a 2-way data binding. Every time the user types something in the EditText, it's updated in the User object as well. Also, refresh the Gradle project so that to generate data binding files like.

In the end, MainActivity uses ViewModel to preserve bound User on config changes. So, you type something and rotate the screen, EditText will keep the text. Here's the code:

public class MainActivity extends AppCompatActivity {
    private UserViewModel viewModel;
    private ActivityMainBinding mainBinding;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mainBinding = DataBindingUtil.setContentView(this,
                R.layout.activity_main);
        mainBinding.setLifecycleOwner(this);

        viewModel = ViewModelProviders.of(this)
                .get(UserViewModel.class);

        viewModel.observeLiveDate(this, user -> {
            // set initial User object
            mainBinding.setUser(user);
        });          
        mainBinding.loadButton.setOnClickListener(v -> {
            // show the current first name 
            Toast.makeText(v.getContext(), "first name : " + mainBinding.getUser().getFirstName(), Toast.LENGTH_LONG).show();
        });
    }
}
Anatolii
  • 14,139
  • 4
  • 35
  • 65
  • thanks for answer but i got error on below lines in MainActivity: mainBinding.setUser(user); mainBinding.loadButton.setOnClickListener(v -> { Toast.makeText(v.getContext(), "first name : " + mainBinding.getUser().getFirstName(), Toast.LENGTH_LONG); in setUser,loadButton,getUser @Anatolii – Reza Abedi Aug 18 '18 at 15:02
  • @R.Abedi no problem. Did you sync the `Gradle` project? – Anatolii Aug 18 '18 at 16:43
  • @R.Abedi I fixed it - I accidentally put `show()` in the wrong place. The answer is updated. – Anatolii Aug 18 '18 at 16:48
  • thanks a lot. i want to do another thing.if u can help me i appreciate that. – Reza Abedi Aug 19 '18 at 06:51
  • @R.Abedi You edited your question by adding the code. Originally, you were asking how to implement it in general. Anyways, what problem do you have with your code? – Anatolii Aug 19 '18 at 07:01
  • Thanks a lot. @Anatolii I want to add textview to xml and update text when `user.firstname` change.but not settext in java.is that possible? i try `android:text="@{user.firstName}"` but nothing change – Reza Abedi Aug 19 '18 at 07:03
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/178283/discussion-between-r-abedi-and-anatolii). – Reza Abedi Aug 19 '18 at 07:12
  • user should not be variable here as viewmodel is used ? – ABDUL RAHMAN Nov 20 '19 at 11:11
  • @ABDULRAHMAN could you please elaborate what you mean? – Anatolii Nov 20 '19 at 11:48
  • observing liveData is a no go in a ViewModel – AndreasReiff Sep 21 '21 at 12:26