Android Databinding not updating UI when data changes in the model - android

I have a model CricketModel
public class CricketModel extends BaseObservable{
private String score;
#Bindable
public String getScore(){
return score
}
public void setScore(String s){
score=s;
notifyPropertyChanged(BR.score);
}
}
When I call API I get JSONArray, I convert them to CricketModel and add it to a CricketModel list. And pass this list to adapter to display them in the Recycler view.
This is my item_cricket.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="cm"
type="com.panasonic.arbohub.cricket.model.CricketModel" />
</data>
<LinearLayout xmlns:app="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:id="#+id/cv_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/dp_8"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
card_view:cardCornerRadius="5dp"
card_view:cardElevation="3dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/tv_two_s_score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/tv_one_p_score"
android:layout_marginEnd="#dimen/dp_16"
android:layout_marginTop="#dimen/dp_8"
android:layout_toStartOf="#+id/rl_team_two"
android:textSize="#dimen/sp_12"
android:textStyle="bold"
android:text="#{cm.score}"
android:visibility="visible" />
</FrameLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</layout>
This is my ViewHolder
private class CricketViewHolder extends RecyclerView.ViewHolder {
ItemCricketBinding itemCricketBinding;
public CricketViewHolder(ItemCricketBinding binding) {
super(binding.getRoot());
itemCricketBinding = binding;
}
public void bind(CricketModel cm){
itemCricketBinding.setCm(cm);
itemCricketBinding.executePendingBindings();
}
}
In my CricketAdapter.java
holder.bind(cricketModelList.get(position));
API updates once in 1 mi, I'm replacing the cricketModelList with new data that is coming from the API but data is not reflecting in the UI.
Have followed this- https://medium.com/google-developers/android-data-binding-recyclerview-db7c40d9f0e4
Update:
After api has been called. I added notifyDataSetChanged() onClickOfthe item view, then new data is reflecting. So model has the new data but its not notifying the UI.

you should set "itemCricketBinding.lifecycleOwner" in bind method, not the best practice and I'm not sure about the performance but if you wonder why that not work, That was the reason.

Related

Control UI visibility on Recycler View item via DataBinding

I am learning MVVM with data binding in Android and got stuck on maintaining UI visibility state of items in the recycler view. Each item sell has 2 text view - title(visible) & description(hidden). Onclick of title, I want to show/hide description. To maintain its UI state, I have a boolean field in the POJO (shared with DB as an entity).
OnClick of title, I am trying to set this field. How can I make the change trigger changing the visibility and maintain it during the scroll?
Here is the Github link for the code and below, the code snippet that I want to work.
Following MVVM architecture with repository to hit network and update DB and observe data via LiveData.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp">
<TextView
android:id="#+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/title"
android:layout_margin="8dp"
android:text="#{posts.desc}"
android:textSize="14sp"
android:visibility="#{(posts.isDescVisible()) ? View.VISIBLE : View.GONE}"
tools:text="This is an answer provided by the creator to test the UI layout" />
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_margin="2dp"
android:ellipsize="end"
android:maxLines="1"
android:onClick="#{()-> posts.setDescVisible(!posts.isDescVisible())}"
android:text="#{posts.title}"
android:textSize="16sp"
android:textStyle="bold"
tools:text="This is a question" />
</RelativeLayout>
<data>
<import type="android.view.View" />
<variable
name="posts"
type="com.tyagiabhinav.loremipsum.model.db.Posts" />
</data>
</layout>
This works well for me
import androidx.databinding.BaseObservable;
public class Posts extends BaseObservable {
private int id;
private final String title;
public final String desc;
private boolean descVisible;
public Posts(String title, String desc) {
this.title = title;
this.desc = desc;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public String getDesc() {
return desc;
}
public void setDescVisible(boolean descVisible) {
this.descVisible = descVisible;
notifyPropertyChanged(BR.descVisible);
}
#Bindable
public boolean isDescVisible() {
return descVisible;
}
}
And the xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp">
<TextView
android:id="#+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/title"
android:layout_margin="8dp"
android:text="#{posts.desc}"
android:textSize="14sp"
***android:visibility="#{posts.descVisible ? View.VISIBLE : View.GONE}"***
tools:text="This is an answer provided by the creator to test the UI layout" />
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_margin="2dp"
android:ellipsize="end"
android:maxLines="1"
android:onClick="#{()-> posts.setDescVisible(!posts.descVisible)}"
android:text="#{posts.title}"
android:textSize="16sp"
android:textStyle="bold"
tools:text="This is a question" />
</RelativeLayout>
<data>
<import type="android.view.View" />
<variable
name="posts"
type="com.tyagiabhinav.loremipsum.model.db.Posts" />
</data>
</layout>

How can I do databinding with livedata?

How can I do databinding with livedata?
activity_user_detail.xml:
<data>
<variable
name="viewModel"
type="com.test.viewmodel.UserViewModel" />
</data>
<TextView
android:id="#+id/tv_amount"
android:layout_width="match_parent"
android:text="#{viewModel.age}"
....
UserViewModel.java:
public class UserViewModel extends ViewModel {
public LiveData<User> user;
public void getUserById(UserDao userDao, String userId){
transaction = UserDao .load(userId);
}
}
UserDao.java:
#Query("SELECT * FROM `user` WHERE id = :userId")
LiveData<User> load(String userId);
UserDetailActivity.java:
private ActivityUserDetailBinding binding;
binding = DataBindingUtil.setContentView(this, R.layout.activity_user_detail);
viewModel = ViewModelProviders.of(this).get(UserViewModel.class);
viewModel.getUserById(userDao, userId);
viewModel.user.observe(this, user -> binding.setViewModel(user)); // How to bind livedata?
I have tried this also:
binding.setViewModel(viewModel);
This is a sample to figure out how LiveData and ObservableField works. You need to change T object and setValue() with LiveData, or set(T) with ObservableField. Changing properties of object T does not update UI.
<?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.example.tutorial3livedata_databinding2objects.UserViewModel" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/user_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text='#{viewModel.userMutableLiveData.name+ ", email " + viewModel.userMutableLiveData.email}'
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.1" />
<EditText
android:id="#+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="48dp"
android:text="#={viewModel.userMutableLiveData.name}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/user_info" />
<EditText
android:id="#+id/et_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="28dp"
android:text="#={viewModel.userMutableLiveData.email}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/et_name" />
<Button
android:id="#+id/button_change_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:onClick="#{() -> viewModel.changeUserName()}"
android:text="Change Name"
app:layout_constraintEnd_toStartOf="#+id/button_change_user"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/et_email" />
<Button
android:id="#+id/button_change_user"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="#{() -> viewModel.changeUser()}"
android:text="Change User"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/button_change_name"
app:layout_constraintTop_toTopOf="#+id/button_change_name" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="56dp"
android:text="Display User"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/button_change_name" />
</android.support.constraint.ConstraintLayout>
</layout>
ViewModel
public class UserViewModel extends ViewModel {
public MutableLiveData<User> userMutableLiveData = new MutableLiveData<>();
private User mUser;
public UserViewModel() {
mUser = new User("User", "asd#abc.com");
userMutableLiveData.setValue(mUser);
}
public void changeUserName() {
// Both updates LiveData but does not update UI
mUser.setName("Name is Changed");
// userMutableLiveData.getValue().setName("Updated Name");
// This one Updates UI
// userMutableLiveData.setValue(userMutableLiveData.getValue());
}
public void changeUser() {
mUser = new User("New User Name", "myemail#mail.com");
// Without setting new value UI is not updated and observe is not called
userMutableLiveData.setValue(mUser);
}
}
MainActivity
/*
Without binding.setLifecycleOwner(this), liveData.setValue() does not update UI
liveData.setValue() updates UI
EditText changes LiveData but does not update UI
*/
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
UserViewModel userViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
// LiveData should call setValue() to update UI via binding
binding.setViewModel(userViewModel);
// Required to update UI with LiveData
binding.setLifecycleOwner(this);
}
}
This code is for learning purposes.
Results you can get from this code:
1- Changing user name with changeUserName() updates the name of existing User of LiveData but does not update UI. UI gets updated when you rotate the device.
2- When you change User of LiveData and setValue() data-binding works.
3- Changing User properties using EditText 2-way binding android:text="#={viewModel.userMutableLiveData.name}" changes LiveData's User's name but does not update UI until device is rotated since User is still same.

How to request or remove the focus on edittext using data binding

I am learning mvvm structure and making an app using mvvm structure and data binding also.
Now, what I want to do is, I wanted to fetch a user from sharedpreference, If I am getting a user successfully then, I would set the name of usr to edittext1. In that case, I want to request focus on edittext2.
How to achieve that using databinding? (in such a way that i don't
have to use activity. The job should be done using view model and xml
only.)
I have tried that using following way.
StartGameViewModel
public class StartGameViewModel extends ViewModel {
public static String TAG="StartGameViewModel";
private Preference<User> preference;
public ObservableField<String> player1Name=new ObservableField<>("");
public ObservableField<String> player2Name=new ObservableField<>("");
public ObservableBoolean shouldRequestFocus=new ObservableBoolean(false);
StartGameViewModel(Preference preference){
this.preference=preference;
}
public void getPreference() {
preference.get(Constants.CURRENT_USER,User.class)
.subscribe(new Observer<User>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(User user) {
player1Name.set(user.name);
shouldRequestFocus.set(true);
}
#Override
public void onError(Throwable e) {
Log.i(TAG,"user is logged out");
}
#Override
public void onComplete() {
Log.i(TAG,"Completed Preference");
}
});
}
}
activity_start_game.xml
<?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"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".view.StartGameActivity">
<data>
<variable
name="startGameViewModel"
type="com.sevenbits.android.mvvmsample.viewmodel.StartGameViewModel" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/splash_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Enter Players Name"
android:textSize="24sp"
android:textColor="#color/white"
app:layout_constraintVertical_bias="0.75"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toTopOf="#+id/input_layout"
app:layout_constraintTop_toTopOf="parent"
/>
<LinearLayout
android:id="#+id/input_layout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:background="#color/white"
android:elevation="20dp"
android:orientation="vertical"
android:paddingBottom="40dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.45"
tools:layout_editor_absoluteX="8dp">
<android.support.design.widget.TextInputLayout
android:id="#+id/til_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<android.support.design.widget.TextInputEditText
android:id="#+id/et_player1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Player1"
android:text="#{startGameViewModel.player1Name}"
app:addTextChangedListener="#{startGameViewModel.Player1Watcher}" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="#+id/til_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<android.support.design.widget.TextInputEditText
android:id="#+id/et_player2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Player2"
android:text="#{startGameViewModel.player2Name}"
app:addTextChangedListener="#{startGameViewModel.Player2Watcher}" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
<Button
android:id="#+id/start_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/bg_button"
android:elevation="20dp"
android:gravity="center"
android:paddingBottom="20dp"
android:paddingEnd="40dp"
android:paddingStart="40dp"
android:paddingTop="20dp"
android:text="Start"
android:textAllCaps="false"
android:textColor="#color/white"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/input_layout" />
</android.support.constraint.ConstraintLayout>
</layout>
StartGameActivity:
public class StartGameActivity extends AppCompatActivity {
ActivityStartGameBinding activityStartGameBinding;
StartGameViewModel startGameViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initDataBinding();
setStartGameListener();
}
private void initDataBinding() {
activityStartGameBinding = DataBindingUtil.setContentView(this, R.layout.activity_start_game);
StartGameViewModelFactory startGameViewModelFactory= Injection.provideStartGameViewModelFactory(this);
startGameViewModel = ViewModelProviders.of(this,startGameViewModelFactory).get(StartGameViewModel.class);
activityStartGameBinding.setStartGameViewModel(startGameViewModel);
startGameViewModel.getPreference();
if(startGameViewModel.shouldRequestFocus.get())
findViewById(R.id.et_player2).requestFocus();
}
private void setStartGameListener() {
findViewById(R.id.start_button).setOnClickListener(v -> {
Intent intent=new Intent(StartGameActivity.this,GameActivity.class);
intent.putExtra(Constants.PLAYER1_NAME,startGameViewModel.player1Name.get());
intent.putExtra(Constants.PLAYER2_NAME,startGameViewModel.player2Name.get());
startActivity(intent);
});
}
}
Very simple via binding adapter
#JvmStatic
#BindingAdapter("requestFocus")
fun requestFocus(view: TextView, requestFocus: Boolean) {
if (requestFocus) {
view.isFocusableInTouchMode = true
view.requestFocus()
}
}
<EditText
android:id="#+id/et_company"
android:layout_width="0dp"
android:layout_height="match_parent"
android:imeOptions="actionDone"
android:inputType="textCapSentences"
android:maxLength="32"
android:scrollbars="vertical"
app:requestFocus="#{company.requestFocus}" />
I know this is an old question, but I was not able to solve the issue with the current answer. Posting my answer here:
in XML:
<EditText
android:id="#+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="#dimen/elevation15"
app:requestFocus="#{viewmodel.focus}"/>
And in the viewModel, I had a Boolean variable declared as
val focus = true
And the binding adapter is as follows:
companion object{
#BindingAdapter("requestFocus")
#JvmStatic fun requestFocus(editText: EditText, requestFocus: Boolean){
if(requestFocus){
editText.isFocusableInTouchMode = true
editText.requestFocus()
}
}
}
Basically what is happening here is, Since app:requestFocus is written inside the xml, it will invoke the binding adapter with the focus Boolean, which is given as the value for the attribute for app:requestFocus.
In my case, I didn't want to remove focus, that's why I used Boolean. If it needs to be changed, using a livedata and set the value, and update the binding adapter accordingly
Disclaimer: I am new to MVVM and Databinding, someone please correct me if I am wrong.

Data failing to display in Firebase Recycler View

I've followed a few different docs to pull together my first Firebase Recycler View:
The two main ones:
Here and here.
I'm using a Message object (included further down) with the Firebase Recycler View. For some reason the data is not displaying. Judging from my log outputs, nothing in the adaptor is being called. Here is the activity code that sits in my onCreate():
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_message_details);
RecyclerView mRecyclerView;
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
Query query = myMessagesRef.child(RoomID)
.orderByKey()
.limitToLast(50);
FirebaseRecyclerOptions<Message> options =
new FirebaseRecyclerOptions.Builder<Message>()
.setQuery(query, Message.class)
.build();
FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter<Message, ChatHolder>(options) {
#Override
public ChatHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Create a new instance of the ViewHolder, in this case we are using a custom
// layout called R.layout.message for each item
final View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_item, parent, false);
return new ChatHolder(view);
}
#Override
protected void onBindViewHolder(ChatHolder holder, int position, Message model) {
//super.onBindViewHolder(holder, position);
Log.w(TAG, "Some Info on messages 2 " + model.MessageText);
holder.bindChat(model);
}
};
mRecyclerView.setAdapter(adapter);
}
Here is my ViewHolder:
static class ChatHolder extends RecyclerView.ViewHolder{
TextView mtext;
//Context mContext;
public ChatHolder(View v) {
super(v);
mtext = (TextView) v.findViewById(com.example.administrationuser.piclo.R.id.textView13);
}
public void bindChat(Message mess){
mtext.setText(mess.MessageText);
}
}
Here is my Message object that I am passing to both Firebase and the adaptor (the data that I input syncs to Firebase with no issue, and my query to firebase gets the data in correct format):
public static class Message {
public String UserID;
public String UserName;
public String MessageText;
public Message() {} // Needed for Firebase
public Message(String UserID, String UserName, String MessageText) {
this.UserID = UserID;
this.UserName = UserName;
this.MessageText = MessageText;
}
}
Here is my Activity Layout XML (with name: activity_message_details.xml):
(note the recycler view near the bottom):
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.administrationuser.piclo.MessageDetails">
<LinearLayout
android:layout_width="395dp"
android:layout_height="643dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:orientation="vertical"
tools:layout_editor_absoluteY="8dp"
tools:layout_editor_absoluteX="8dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="150dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<EditText
android:id="#+id/editText3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:text="Name"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<Button
android:id="#+id/button9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Button"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:onClick="onClick"/>
</RelativeLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawSelectorOnTop="false"
/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
Finally, here is my View layout XML (with name: recycler_item.xml):
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView13"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
</FrameLayout >
There were two things that needed fixing.
1) Adding in the adapter.startListening(); (as mentioned by Elvin No Matter). In my case I added this just below the mRecyclerView.setAdapter(adapter); near the end of my onCreate.
2) Enclosing my View Layout XML in a <android.support.v7.widget.LinearLayoutCompat>. See my new View Holder, with some other irrelevant changes to the buttons:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp">
<TextView
android:id="#+id/textView13"
android:layout_width="285dp"
android:layout_height="24dp"
android:text="TextView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
tools:layout_editor_absoluteX="-6dp" />
<TextView
android:id="#+id/textView14"
android:layout_width="123dp"
android:layout_height="24dp"
android:layout_alignParentTop="true"
android:layout_marginRight="8dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="#+id/textView13"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="154dp" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.LinearLayoutCompat>
according to readme
The FirestoreRecyclerAdapter uses a snapshot listener to monitor
changes to the Firestore query. To begin listening for data, call the
startListening() method. You may want to call this in your onStart()
method. Make sure you have finished any authentication necessary to
read the data before calling startListening() or your query will fail.
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
and
#Override
protected void onStop() {
super.onStop();
adapter.stopListening();
}

Android Data Binding Recycler View twitches after adding element

I have fragment with RecycleView and Floating Action Button to add new object.
POJO:
public class MockCar extends BaseObservable {
private String name;
private String plateNumber;
public MockCar(String name, String plateNumber) {
this.name = name;
this.plateNumber = plateNumber;
}
#Bindable
public String getName() {
return name;
}
#Bindable
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.car);
}
#Bindable
public String getPlateNumber() {
return plateNumber;
}
#Bindable
public void setPlateNumber(String plateNumber) {
this.plateNumber = plateNumber;
notifyPropertyChanged(BR.car);
}
}
item.xml
<?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="car"
type="com.igor.touchless.model.MockCar"/>
<variable
name="click"
type="com.igor.touchless.adapter.interfaces.CarClickHandler"/>
</data>
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="72dp"
android:layout_gravity="center"
android:padding="4dp"
android:background="#FFF"
card_view:cardCornerRadius="6dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="#{car.name}"
android:textColor="#color/primary_text"
android:textSize="18sp" />
<TextView
android:id="#+id/plate_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/name"
android:text="#{car.plateNumber}"
android:textColor="#color/secondary_text"
android:textSize="13sp" />
<ImageView
android:id="#+id/button_edit"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentRight="true"
android:background="#color/primary"
android:src="#drawable/ic_create_black_24dp"
app:civ_border_color="#00EEEEEE"
app:civ_border_width="0dp"
app:civ_shadow="false"
app:civ_shadow_color="#008BC34A"
app:civ_shadow_radius="0" />
<ImageView
android:id="#+id/button_remove"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="#F44336"
android:src="#drawable/ic_clear_black_24dp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</layout>
After pressing floating action button I add new item to collection
public void add(MockCar car) {
carList.add(car);
notifyDataSetChanged();
}
The problem is next - when I try to add elements more then can fit in the screen (8th and all next) I can see that recycler view twitches, doesn't matter I am at the beginning of the list or at the end. As far as I understand it updated all views if I update ArrayList or try to change any property of the object. I assume I made something wrong with it notifyPropertyChanged(BR.car), but have no idea how to deal with it.
If I use standard approach everything works as expected.
I just started learning android data binding. Sure somebody has already faced with this problem. Thanks in advance.

Categories

Resources