Reputation: 386
I have a RecyclerView
that has many cards that hold 4 EditText
. When I input values in one EditText
of one card, it fills the same value in random cards. Surprisingly it does not jump EditText
s for example:
If I input values in edittext1
of card1
it would fill the same value into edittext1
in card8
and if I change the value in card8
it will change the value back in card1
. Could someone please tell me why this is happening.
Thank You in Advance
Here is my code:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private String[] mDataset;
public String[][] data = new String[30][4];
public static class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public LinearLayout mCardView;
public ViewHolder(LinearLayout v) {
super(v);
mCardView = v;
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(String[] myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
LinearLayout v = (LinearLayout) LayoutInflater.from(parent.getContext())
.inflate(R.layout.cards, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final EditText txt = (EditText) holder.mCardView.findViewById(R.id.ip1_text);
final EditText txt2 = (EditText) holder.mCardView.findViewById(R.id.ip2_text);
final EditText txt3 = (EditText) holder.mCardView.findViewById(R.id.ip3_text);
final EditText txt4 = (EditText) holder.mCardView.findViewById(R.id.ip4_text);
txt.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
data[position][0] = s.toString();
Log.d("DATA" + position + "0", s.toString());
}
});
txt2.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
data[position][1] = s.toString();
Log.d("DATA" + position + "1", s.toString());
}
});
txt3.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
data[position][2] = s.toString();
Log.d("DATA" + position + "2", s.toString());
}
});
txt4.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
data[position][3] = s.toString();
Log.d("DATA" + position + "3", s.toString());
}
});
TextView t = (TextView) holder.mCardView.findViewById(R.id.serNo);
t.setText(mDataset[position]);
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return mDataset.length;
}
public String[][] getData() {
return data;
}
And this is my card xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:weightSum="1">
<!-- A CardView that contains a TextView -->
<android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_width="375dp"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:backgroundTint="#eeeeee"
card_view:cardCornerRadius="4dp">
<TextView
android:id="@+id/serNo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="number"
android:layout_margin="20dp"
android:textColor="@color/cardview_dark_background" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<EditText
android:id="@+id/ip1_text"
android:layout_width="100dp"
android:layout_height="30dp"
android:layout_alignParentLeft="true"
android:layout_marginTop="20dp"
android:background="@color/cardview_light_background"
android:inputType="number"
android:maxLength="2" />
<EditText
android:id="@+id/ip3_text"
android:layout_width="80dp"
android:layout_height="30dp"
android:layout_below="@+id/ip1_text"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:background="@color/cardview_light_background"
android:inputType="number"
android:maxLength="1" />
<EditText
android:id="@+id/ip2_text"
android:layout_width="100dp"
android:layout_height="30dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_toRightOf="@+id/ip1_text"
android:background="@color/cardview_light_background"
android:inputType="number"
android:maxLength="2" />
<EditText
android:id="@+id/ip4_text"
android:layout_width="80dp"
android:layout_height="30dp"
android:layout_below="@+id/ip2_text"
android:layout_marginBottom="10dp"
android:layout_marginLeft="40dp"
android:layout_marginTop="10dp"
android:layout_toRightOf="@+id/ip3_text"
android:background="@color/cardview_light_background"
android:inputType="number"
android:maxLength="1" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
Upvotes: 3
Views: 9006
Reputation: 81
This is Issue For Recycler View Recycle Just Override these function
@Override
public long getItemId(int position) {
return position;
}
@Override public int getItemViewType(int position) {
return position;
}
Upvotes: 0
Reputation: 238
When you set data you should use getAdapterPosition() instead of position. This is because when the recyclerview scrolled, it recycled and the position will not get the correct value.
data[getAdapterPosition()][1] = s.toString();
Upvotes: 0
Reputation: 93
I used to OnFocusChangeListener in onBindViewHolder for adapter
editText.setText(mValues.get(position).getValue());
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus)
mValues.get(position).setValue(editText.getText().toString());
}
});
Upvotes: 0
Reputation: 2512
That happens because the views inside a RecyclerView
are being recycled. Inside the onBindViewHolder
you need to set the specific texts to the EditTexts at the specific position.
Initialize your Views inside the ViewHolder
and add the TextWatchers there as the whole philosophy of the RecyclerView
is to reuse the views :
public static class ViewHolder extends RecyclerView.ViewHolder {
EditText txt;
EditText txt2;
EditText txt3;
EditText txt4;
TextView serNoTxt;
public ViewHolder(LinearLayout mCardView) {
super(mCardView);
txt = (EditText) mCardView.findViewById(R.id.ip1_text);
txt2 = (EditText) mCardView.findViewById(R.id.ip2_text);
txt3 = (EditText) mCardView.findViewById(R.id.ip3_text);
txt4 = (EditText) mCardView.findViewById(R.id.ip4_text);
setNoTxt = (TextView) mCardView.findViewById(R.id.serNo);
txt.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
data[getAdapterPosition()][0] = s.toString();
Log.d("DATA" + getAdapterPosition() + "0", s.toString());
}
});
txt2.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
data[getAdapterPosition()][1] = s.toString();
Log.d("DATA" + getAdapterPosition() + "1", s.toString());
}
});
txt3.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
data[getAdapterPosition()][2] = s.toString();
Log.d("DATA" + getAdapterPosition() + "2", s.toString());
}
});
txt4.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
data[getAdapterPosition()][3] = s.toString();
Log.d("DATA" + getAdapterPosition() + "3", s.toString());
}
});
}
}
Set the appropriate text to the EditTexts in the onBindViewHolder
:
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.txt1.setText(data[position][0]);
holder.txt2.setText(data[position][1]);
holder.txt3.setText(data[position][2]);
holder.txt4.setText(data[position][3]);
holder.setNoTxt.setText(mDataset[position]);
}
Upvotes: 10
Reputation: 5480
You updated the data without notifying the adapter. This could create inconsistencies. So after the data is changed you should call notifyItemChanged()
.
For example:
@Override
public void afterTextChanged(Editable s) {
data[position][3] = s.toString();
Log.d("DATA" + position + "3", s.toString());
notifyItemChanged(position);
}
One more suggestion I have is to reuse the code so you won't have to copy paste so much and fix in many places (for example, all of your TextWatcher objects are basically the same).
Upvotes: 1