'I am stuck getting the values from EditTexts in Recyclerview and then store them as array?
Firebase screenshot Recyclerview screenshot I am trying to get the values from the editTexts on each row in my RecyclerView. I have seen many post suggesting use of TextWatcher but I am not sure how to implement it. I am newbie. I am loading the questions and the equations from my firebase and I need to compare the results provided. Could anyone help me?
my Adapter
public class ExamAdapter extends RecyclerView.Adapter<ExamAdapter.ExamHolder> {
ArrayList<QuestionModel> listQ;
public ExamAdapter(ArrayList<QuestionModel> listQ) {
this.listQ = listQ;
}
@NonNull
@Override
public ExamHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_exam,parent,false);
return new ExamHolder(v);
}
@Override
public void onBindViewHolder(@NonNull ExamHolder holder, int position) {
holder.question.setText(listQ.get(position).getName());
holder.equation.setText(listQ.get(position).getEquation());
holder.answer.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) {
holder.answer.setText(s.toString());
}
});
}
@Override
public int getItemCount() {
return listQ.size();
}
@Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
public static class ExamHolder extends RecyclerView.ViewHolder{
TextView question, equation;
EditText answer;
public ExamHolder(@NonNull View itemView) {
super(itemView);
question = itemView.findViewById(R.id.tv_questionExam);
equation = itemView.findViewById(R.id.tv_equationExam);
answer = itemView.findViewById(R.id.et_examResult);
}
}
public List<QuestionModel> retrieveAnswers(){
return listQ;
}
}
my activity
public class StudentExam extends DrawerActivity {
Button btnSubmit;
TextView tvExam;
ArrayList<QuestionModel> listQ = new ArrayList<>();
ExamAdapter adapter;
RecyclerView recyclerView;
DatabaseReference dbref;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_student_exam);
LayoutInflater inflater = LayoutInflater.from(this);
View v = inflater.inflate(R.layout.activity_student_exam,null,false);
drawer.addView(v,0);
btnSubmit = findViewById(R.id.btn_SubmitExam);
tvExam = findViewById(R.id.tv_examLogo);
Intent i = getIntent();
String schoolName = i.getExtras().getString("school");
recyclerView = findViewById(R.id.rv_TakeExam);
recyclerView.setLayoutManager(new LinearLayoutManager(StudentExam.this));
dbref = FirebaseDatabase.getInstance().getReference("Exams").child(schoolName).child("test5");
dbref.addListenerForSingleValueEvent(listener);
btnSubmit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<QuestionModel> answers = adapter.retrieveAnswers();
}
});
}
ValueEventListener listener = new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
for(DataSnapshot dss: snapshot.getChildren()){
QuestionModel q = dss.getValue(QuestionModel.class);
listQ.add(q);
adapter = new ExamAdapter(listQ);
recyclerView.setAdapter(adapter);
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
};
}
and my QuestionModel class
public class QuestionModel {
String equation, name, result;
public QuestionModel() {
}
public QuestionModel(String equation, String result, String name) {
this.equation = equation;
this.result = result;
this.name = name;
}
public String getEquation() {
return equation;
}
public void setEquation(String equation) {
this.equation = equation;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
Solution 1:[1]
RecyclerView reuses views as you can see on this picture:
To make your code work properly you should take this into account. You need to correctly setup your view in every onBindViewHolder call, because single view can be used for displaying different items. So to not lose answer values you need to keep them in some place.
You can for ex. add a String field with name answer in your QuestionModel, then you modify your code like this:
@Override
public void onBindViewHolder(@NonNull ExamHolder holder, int position) {
holder.question.setText(listQ.get(position).getName());
holder.equation.setText(listQ.get(position).getEquation());
//Add this line
holder.answer.setText(listQ.get(position).answer);
holder.answer.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) {
holder.answer.setText(s.toString());
//Add this line too!
listQ.get(holder.getAbsoluteAdapterPosition()).answer = s.toString();
}
});
}
After that everything should work properly, but there is one another hidden issue. Every time you scroll the RecyclerView and `onBindViewHolder` is called a new TextWatcher is added (line: `holder.answer.addTextChangedListener(new TextWatcher())`) it may cause some weird bugs.
To prevent that you need to remove old `TextWatcher` before adding a new one (or don't add new one) to make sure every editext has only one text watcher.
To do that you can modify your `ExamHolder`:
public static class ExamHolder extends RecyclerView.ViewHolder {
TextView question, equation;
EditText answer;
TextWatcher watcher;
public ExamHolder(@NonNull View itemView) {
super(itemView);
question = itemView.findViewById(R.id.tv_questionExam);
equation = itemView.findViewById(R.id.tv_equationExam);
answer = itemView.findViewById(R.id.et_examResult);
}
public void setTextWatcher(TextWatcher textWatcher) {
if(answer != null && this.watcher != null)
answer.removeTextChangedListener(watcher);
this.watcher = textWatcher;
}
}
Then you also need to modify your `onBindViewHolder`:
@Override
public void onBindViewHolder(@NonNull ExamHolder holder, int position) {
holder.question.setText(listQ.get(position).getName());
holder.equation.setText(listQ.get(position).getEquation());
//Add this line
holder.answer.setText(listQ.get(position).answer);
//Change this line
holder.setTextWatcher(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) {
holder.answer.setText(s.toString());
listQ.get(holder.getAbsoluteAdapterPosition()).answer = s.toString();
}
});
}
Now your RecyclerView should work perfectly!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jan Rozenbajgier |
