I have a fragment, which contains a recyclerview. This recyclerview is managed with an adapter that includes the viewholder pattern.
In the fragment I have a "Save" button, this button must check that no TextInputEditText is empty in the list.
The problem is that I can not access the TextInputEditText of the adapter. ViewHolder is only accessible from the "onBindViewHolder" method.
I tried to access from fragment in a way:
for (int i = 0; i < employeeList.size(); i++) {
View employeeView = recyclerEmployees.findViewHolderForAdapterPosition(i).itemView;
if (employeeView != null) {
TextInputLayout textInputLayoutName = employeeView.findViewById(R.id.tilName);
TextInputEditText textInputEditTextName = employeeView.findViewById(R.id.tieName);
By doing this I have managed to mark error in the TextInputLayout. I have also been able to get the text of the TextInputEditText. Everything seemed to work, but ...
The problem appears when the list changes and I need to refresh the adapter by calling notifyDataSetChanged
findViewHolderForAdapterPosition
returns null in some positions of the list.
I read in some post that it is not safe to call that method
https://stackoverflow.com/a/32840927/1484779
I have also read that it is not a good practice to access the viewholder
outside the onBindViewHolder
method.
Can anyone help me get this? It does not seem difficult but it is causing me a great waste of time.
I just want to click on my save button in the fragment and check that no TextInputEditText
is empty in the list of items in my recyclerview
Thanks
Try this
AddMoreAdapter
public class AddMoreAdapter extends RecyclerView.Adapter<AddMoreAdapter.ViewHolder> {
Context context;
ArrayList<AddMorePojo> arrayList;
public AddMoreAdapter(Context context, ArrayList<AddMorePojo> arrayList) {
this.context = context;
this.arrayList = arrayList;
}
@Override
public AddMoreAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.addmorelayout, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(AddMoreAdapter.ViewHolder holder, int position) {
Log.e("VALUE ", arrayList.get(position).getUserName());
if (!TextUtils.isEmpty(arrayList.get(position).getUserName())) {
holder.edtName.setText(arrayList.get(position).getUserName());
}
if (!TextUtils.isEmpty(arrayList.get(position).getError())) {
holder.edtName.setError(arrayList.get(position).getError());
} else {
holder.edtName.setError(null);
}
}
@Override
public int getItemCount() {
return arrayList.size();
}
public ArrayList<AddMorePojo> getArrayList() {
return arrayList;
}
public class ViewHolder extends RecyclerView.ViewHolder {
EditText edtName;
public ViewHolder(View itemView) {
super(itemView);
edtName = itemView.findViewById(R.id.edtUname);
edtName.addTextChangedListener(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) {
arrayList.get(getAdapterPosition()).setUserName(charSequence.toString());
}
@Override
public void afterTextChanged(Editable editable) {
}
});
}
}
}
AddMorePojo
public class AddMorePojo
{
String userName,error;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
}
MyActivity
public class MyActivity extends AppCompatActivity {
RecyclerView myRc;
ArrayList<AddMorePojo> arrayList = new ArrayList<>();
Button btnGetData;
AddMoreAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
myRc = (RecyclerView) findViewById(R.id.myRc);
btnGetData = (Button) findViewById(R.id.btnGetData);
myRc.setHasFixedSize(true);
myRc.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
AddMorePojo addMorePojo = new AddMorePojo();
addMorePojo.setUserName("");
arrayList.add(addMorePojo);
AddMorePojo addMorePojo1 = new AddMorePojo();
addMorePojo1.setUserName("");
addMorePojo1.setError("");
arrayList.add(addMorePojo1);
AddMorePojo addMorePojo2 = new AddMorePojo();
addMorePojo2.setUserName("");
addMorePojo2.setError("");
arrayList.add(addMorePojo2);
adapter = new AddMoreAdapter(this, arrayList);
myRc.setAdapter(adapter);
btnGetData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
boolean flag=true;
ArrayList<AddMorePojo> pojoArrayList = adapter.getArrayList();
for (int i = 0; i < pojoArrayList.size(); i++) {
if (pojoArrayList.get(i).getUserName().isEmpty()) {
pojoArrayList.get(i).setError("Please enter userName");
flag=false;
}else {
// pojoArrayList.get(i).setError("");
}
}
adapter = new AddMoreAdapter(MyActivity.this, pojoArrayList);
myRc.setAdapter(adapter);
if (flag){
Toast.makeText(MyActivity.this, "Valid data", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MyActivity.this, "Invalid data", Toast.LENGTH_SHORT).show();
}
}
});
}
}
layout.activity_my
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<android.support.v7.widget.RecyclerView
android:id="@+id/myRc"
android:layout_width="match_parent"
android:paddingBottom="50dp"
android:layout_height="match_parent" />
<Button
android:id="@+id/btnGetData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:gravity="center"
android:layout_alignParentBottom="true"
android:text="Get Data" />
</RelativeLayout>
addmorelayout
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardElevation="10dp"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/edtUname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter User Name" />
</LinearLayout>
</android.support.v7.widget.CardView>
Yes you are right its not difficult.
@Override
public void onBindView(Object object, int pos) {
Employee employee = (Employee) object;
editText.addTextChangedListener(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) {
employee.setName(charSequence.toString());
}
@Override
public void afterTextChanged(Editable editable) {
}
});
}
And on save button get value from list.
You can use a boolean field in your model for example.
class TestData{
private boolean isTextEmpty;
private String textData;
public void setTextEmpty(boolean isTrue){
isTextEmpty = isTrue;
}
public boolean isTextEmpty(){
return isTextEmpty;
}
public void setTextData(String data){
textData = data;
}
public void getData(){
return textData;
}
........
///other fields goes here
}
now use this model in your list and fed it to adapter
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.ViewHolder> {
ArrayList<TestData> arrayList;
boolean isSubmitClick = false;
public AddMoreAdapter(ArrayList<TestData> arrayList) {
this.arrayList = arrayList;
}
@Override
public TestAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.test_data_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(TestAdapter.ViewHolder holder, int position) {
TestData data = arrayList.get(holder.getAdapterPosition());
if (holder.editText.getText().toString()==null) {
if(isSubmitClick){
holder.inputText.setError("please enter a valid input");
}
data.setTextEmpty(true);
} else {
data.setTextEmpty(false);
//do something else
}
}
@Override
public int getItemCount() {
return arrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextInputLayout textInput;
EditText editName;
public ViewHolder(View itemView) {
super(itemView);
editName = itemView.findViewById(R.id.etTest);
textInput = itemView.findViewById(R.id.tilTest);
editName.addTextChangedListener(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) {
arrayList.get(getAdapterPosition()).setTestData(editable.toString());
}
});
}
}
public void setSubmitClick(boolean isTrue){
this.isSubmitClick = isTrue;
}
}
now in your fragment do like this call adapter.setSubmitClick(true);
on click of your button and then validate the data like below.
public void isDataValid(){
for(int i = 0; i<arrayList.size(); i++){
TestData data = arrayList.get(i);
if(data.isTextEmpty()){
adapter.notifyItemChanged(i);
return;
}
}
//do something here as all data is valid
callServer();
}