Guardar el contenido de EditText en RecyclerView

Tengo un elemento de la lista con EditText , no sé cuántos elementos habrá. Tengo un problema cuando ingreso un texto en EditText , y luego me EditText hacia abajo en RecyclerView ; luego de volver a desplazarme hacia arriba, no aparece texto en mi primer EditText .

Me pregunto qué, y dónde debería escribir código para que mientras el usuario esté escribiendo o termine de escribir (estaba pensando en hacer eso con un TextWatcher ) en EditText el texto se guarde en un archivo (lo EditText en un archivo .txt en el almacenamiento externo)

¿Se supone que debo hacerlo en el método onCreate de la actividad o en la clase de adaptador o en otro lugar?

Aquí hay un código

Código de actividad principal

  public class MainActivity extends Activity { RecyclerView mRecyclerView; MyAdapter mAdapter; String[] mDataSet= new String[20]; @Override protected void onCreate(Bundle savedInstanceState) { // generating text for editText Views for (int i = 0; i<=19; i++){ mDataSet[i]= "EditText n: "+i; } super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view); mAdapter = new MyAdapter(mDataSet); mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mRecyclerView.setAdapter(mAdapter); mRecyclerView.setHasFixedSize(true); } 

Mi código de adaptador

 public class MyAdapter extends RecyclerView.Adapter { private String[] mDataset; public static class ViewHolder extends RecyclerView.ViewHolder { // each data item is just a string in this case public EditText mEditText; public ViewHolder(View v) { super(v); mEditText = (EditText) v.findViewById(R.id.list_item_edittext); } } public MyAdapter(String[] myDataset) { mDataset = myDataset; } @Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_item, parent, false); ViewHolder vh = new ViewHolder(v); return vh; } @Override public void onBindViewHolder(ViewHolder holder, final int position) { holder.mEditText.setText(mDataset[position]); //without this addtextChangedListener my code works fine ovbiusly // not saving the content of the edit Text when scrolled // If i add this code then when i scroll all textView that go of screen // and than come back in have messed up content holder.mEditText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { //setting data to array, when changed // this is a semplified example in the actual app i save the text // in a .txt in the external storage mDataset[position] = s.toString(); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { } }); } @Override public int getItemCount() { return mDataset.length; } 

sin este “addtextChangedListener”, mi código funciona bien, obviamente, no guarda el contenido del texto de edición cuando se desplaza. Si agrego este código, cuando me desplazo por todas las vistas de edición de texto que salen de la pantalla y vuelvo a tener contenido desordenado.

El principal problema con su solución es asignar y asignar TextWatcher en onBindViewHolder, que es una operación costosa que introducirá retrasos durante los desplazamientos rápidos y también parece interferir con la determinación de qué posición actualizar en mAdapter.

Hacer todas las operaciones en onCreateViewHolder es una opción más preferible. Aquí está la solución de trabajo probada completa:

 public class MyAdapter extends RecyclerView.Adapter { private String[] mDataset; public MyAdapter(String[] myDataset) { mDataset = myDataset; } @Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_edittext, parent, false); // pass MyCustomEditTextListener to viewholder in onCreateViewHolder // so that we don't have to do this expensive allocation in onBindViewHolder ViewHolder vh = new ViewHolder(v, new MyCustomEditTextListener()); return vh; } @Override public void onBindViewHolder(ViewHolder holder, final int position) { // update MyCustomEditTextListener every time we bind a new item // so that it knows what item in mDataset to update holder.myCustomEditTextListener.updatePosition(holder.getAdapterPosition()); holder.mEditText.setText(mDataset[holder.getAdapterPosition()]); } @Override public int getItemCount() { return mDataset.length; } public static class ViewHolder extends RecyclerView.ViewHolder { // each data item is just a string in this case public EditText mEditText; public MyCustomEditTextListener myCustomEditTextListener; public ViewHolder(View v, MyCustomEditTextListener myCustomEditTextListener) { super(v); this.mEditText = (EditText) v.findViewById(R.id.editText); this.myCustomEditTextListener = myCustomEditTextListener; this.mEditText.addTextChangedListener(myCustomEditTextListener); } } // we make TextWatcher to be aware of the position it currently works with // this way, once a new item is attached in onBindViewHolder, it will // update current position MyCustomEditTextListener, reference to which is kept by ViewHolder private class MyCustomEditTextListener implements TextWatcher { private int position; public void updatePosition(int position) { this.position = position; } @Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { // no op } @Override public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { mDataset[position] = charSequence.toString(); } @Override public void afterTextChanged(Editable editable) { // no op } } } 

Tuve el mismo problema, agregué la siguiente línea y parece que resolvió el problema de mi lado.

 mRecyclerview.setItemViewCacheSize(mDataset.size()); 

Espero que esto resuelva el problema de tu lado.

Cree una matriz de cadenas con el tamaño de los datos de su adaptador.

Ejemplo: String[] texts = new String[dataSize];

en el método onBindViewHolder dentro de su adaptador, agregue un TextChangedListener a Textview.

P.ej : –

 @Override public void onBindViewHolder(Viewholder holder, int position) { //binding data from array holder.yourEditText.setText(texts [position]); holder.yourEditText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { //setting data to array, when changed texts [position] = s.toString(); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { //blank } @Override public void afterTextChanged(Editable s) { //blank } }); } 

Crearía una interfaz y pasaría la posición actual del adaptador para manejar el evento de cambio de texto

  public class MyAdapter extends RecyclerView.Adapter { private String[] mDataset; public MyAdapter(String[] myDataset) { mDataset = myDataset; } @Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_edittext, parent, false); ViewHolder vh = new ViewHolder(v, new ViewHolder.ITextWatcher() { @Override public void beforeTextChanged(int position, CharSequence s, int start, int count, int after) { // do something } @Override public void onTextChanged(int position, CharSequence s, int start, int before, int count) { mDataset[position] = s.toString(); } @Override public void afterTextChanged(int position, Editable s) { // do something } }); return vh; } @Override public void onBindViewHolder(ViewHolder holder, final int position) { holder.mEditText.setText(mDataset[position]); } @Override public int getItemCount() { return mDataset.length; } public static class ViewHolder extends RecyclerView.ViewHolder { public EditText mEditText; private ITextWatcher mTextWatcher; public interface ITextWatcher { // you can add/remove methods as you please, maybe you dont need this much void beforeTextChanged(int position, CharSequence s, int start, int count, int after); void onTextChanged(int position, CharSequence s, int start, int before, int count); void afterTextChanged(int position, Editable s); } public ViewHolder(View v, ITextWatcher textWatcher) { super(v); this.mEditText = (EditText) v.findViewById(R.id.editText); this.mTextWatcher = textWatcher; this.mEditText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { mTextWatcher.beforeTextChanged(getAdapterPosition(), s, start, count, after); } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mTextWatcher.onTextChanged(getAdapterPosition(), s, start, before, count); } @Override public void afterTextChanged(Editable s) { mTextWatcher.afterTextChanged(getAdapterPosition(), s); } }); } } } 

No estoy tan familiarizado con los objetos RecyclerView, pero tuve el mismo problema con ListView. Para esos, generalmente creo una clase ad-hoc que representa los valores insertados en mis vistas (funciona con EditTexts, Checkboxes, RadioButtons …) y obtengo datos actualizados a través de ellos. Luego creo un ArrayAdapter personalizado que consiste en dichos objetos contenedor, recuperando valores para poner en los edittexts en cada callback getView () de ellos e implementando un textwatcher para mantener estos objetos actualizados. De nuevo, no recuerdo exactamente cómo funcionan las RecyclerViews, pero si involucran Adapters, podría ser un buen truco para que lo pruebes.

Hola, @mikwee, asegúrate de que estás agregando oyente de texto modificado en el siguiente método en lugar de agregarlo a onBindViewHolder ().

 public ViewHolder(View v) { super(v); yourEditText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { //setting data to array, when changed texts [position] = s.toString(); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { } }); } 

Según yo, esto es más optimista de la respuesta de @dkarmazi

 public class UploadPhotoAdapter extends RecyclerView.Adapter { ArrayList feeds; Activity activity; public UploadPhotoAdapter(Activity activity, ArrayList feeds) { this.feeds = feeds; this.activity = activity; } @Override public UploadPhotoAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.upload_feeds_recycler, parent, false); return new UploadPhotoAdapter.MyViewHolder(itemView); } @Override public void onBindViewHolder(final UploadPhotoAdapter.MyViewHolder holder, int position) { Feed feed = feeds.get(holder.getAdapterPosition()); holder.captionEditText.setText(feed.getDescription()); holder.captionEditText.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) { feeds.get(holder.getAdapterPosition()).setDescription(s.toString()); } @Override public void afterTextChanged(Editable s) {} }); } @Override public int getItemCount() { return feeds.size(); } public class MyViewHolder extends RecyclerView.ViewHolder { EditText captionEditText; public MyViewHolder(View view) { super(view); captionEditText = (EditText) view.findViewById(R.id.captionEditText); } } } 

Simplemente anule el siguiente método para resolver el problema:

 @Override public int getItemViewType(final int position) { return position; }