Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement Livedata and Databinding in Android?

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

like image 774
Reza Abedi Avatar asked Aug 18 '18 08:08

Reza Abedi


1 Answers

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();
        });
    }
}
like image 150
Anatolii Avatar answered Nov 16 '22 01:11

Anatolii