Cómo eliminar todos los oyentes añadidos con addTextChangedListener

Tengo un ListView donde cada fila tiene un control EditText . Quiero agregar un TextChangedListener a cada fila; uno que contiene datos adicionales que dicen en qué fila estaba EditText . El problema es que cuando se llama a TextWatchers se agregan varios TextWatchers ; porque el convertView ya tiene un TextWatcher (y uno que apunta a una fila diferente).

 MyTextWatcher watcher = new MyTextWatcher(currentQuestion); EditText text = (EditText)convertView.findViewById(R.id.responseText); text.addTextChangedListener(watcher); 

MyTextWatcher es mi clase que implementa TextWatcher ; y maneja los eventos de texto. CurrentQuestion me permite saber en qué fila estoy actuando. Cuando escribo en el cuadro; se TextWatcher varias instancias de TextWatcher .

¿Hay alguna forma de eliminar TextWatchers antes de agregar uno nuevo? Veo el método removeTextChangedListener , pero eso requiere que se TextWatcher un TextWatcher específico, y no sé cómo obtener el puntero al TextWatcher que ya está allí.

No hay forma de hacer esto usando la interfaz EditText actual directamente. Veo dos posibles soluciones:

  1. Rediseña tu aplicación para que siempre sepas qué TextWatcher se agrega a una instancia particular de EditText .
  2. Extiende EditText y agrega la posibilidad de borrar a todos los observadores.

Aquí hay un ejemplo de segundo enfoque: ExtendedEditText :

 public class ExtendedEditText extends EditText { private ArrayList mListeners = null; public ExtendedEditText(Context ctx) { super(ctx); } public ExtendedEditText(Context ctx, AttributeSet attrs) { super(ctx, attrs); } public ExtendedEditText(Context ctx, AttributeSet attrs, int defStyle) { super(ctx, attrs, defStyle); } @Override public void addTextChangedListener(TextWatcher watcher) { if (mListeners == null) { mListeners = new ArrayList(); } mListeners.add(watcher); super.addTextChangedListener(watcher); } @Override public void removeTextChangedListener(TextWatcher watcher) { if (mListeners != null) { int i = mListeners.indexOf(watcher); if (i >= 0) { mListeners.remove(i); } } super.removeTextChangedListener(watcher); } public void clearTextChangedListeners() { if(mListeners != null) { for(TextWatcher watcher : mListeners) { super.removeTextChangedListener(watcher); } mListeners.clear(); mListeners = null; } } } 

Y aquí está cómo puede usar ExtendedEditText en diseños xml:

     

Puede eliminar TextWatcher de su EditText. Antes que nada, te sugiero que muevas la statement de TextWatcher fuera de editText.addTextChangedListener (…):

 protected TextWatcher yourTextWatcher = new TextWatcher() { @Override public void afterTextChanged(Editable s) { // your logic here } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // your logic here } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // your logic here } }; 

Después de eso, podrás configurar TextWather un poco más simple:

 editText.addTextChangedListener(yourTextWatcher); 

Entonces puedes eliminar TextWatcher de la siguiente manera:

 editText.removeTextChangedListener(yourTextWatcher); 

y establecer otro si lo desea.

También pasé mucho tiempo buscando la solución y finalmente terminé solucionando con la ayuda de la etiqueta como a continuación. Eliminaría las instancias anteriores de TextWatcher al obtener referencias de la etiqueta de convertView. Resuelve perfectamente el problema. En su archivo CustomAdapter, establezca una nueva clase interna como a continuación:

 private static class ViewHolder { private TextChangedListener textChangedListener; private EditText productQuantity; public EditText getProductQuantity() { return productQuantity; } public TextChangedListener getTextChangedListener() { return textChangedListener; } public void setTextChangedListener(TextChangedListener textChangedListener) { this.textChangedListener = textChangedListener; } } 

Luego, en su método público anulado getView (int position, View convertView, ViewGroup parent) implemente la lógica como a continuación:

 @Override public View getView(int position, View convertView, ViewGroup parent) { EditText productQuantity; TextChangedListener textChangedListener; if(convertView==null) { LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE); convertView = mInflater.inflate(R.layout.cart_offer_item, parent, false); productQuantity=(EditText)convertView.findViewById(R.id.productQuantity); addTextChangedListener(viewHolder, position); convertView.setTag(viewHolder); } else { ViewHolder viewHolder=(ViewHolder)convertView.getTag(); productQuantity=viewHolder.getProductQuantity(); removeTextChangedListener(viewHolder); addTextChangedListener(viewHolder, position); } return convertView; } private void removeTextChangedListener(ViewHolder viewHolder) { TextChangedListener textChangedListener=viewHolder.getTextChangedListener(); EditText productQuantity=viewHolder.getProductQuantity(); productQuantity.removeTextChangedListener(textChangedListener); } private void addTextChangedListener(ViewHolder viewHolder, int position) { TextChangedListener textChangedListener=new TextChangedListener(position); EditText productQuantity=viewHolder.getProductQuantity(); productQuantity.addTextChangedListener(textChangedListener); viewHolder.setTextChangedListener(textChangedListener); } 

Luego, implemente la clase TextWatcher de la siguiente manera:

 private class TextChangedListener implements TextWatcher { private int position; TextChangedListener(int position) { this.position=position; } @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) { Log.d("check", "text changed in EditText"); } } 

Eliminaría las instancias previas de TextWatcher al obtener referencias de la etiqueta de convertView

Guarde el verificador de texto actual en el visor y puede encontrar el que desea eliminar.

Tuve el mismo problema con xamarin / C # y escribí para esta clase una clase para administrar los eventos de clic dentro de un ListView donde la vista del elemento se “reciclará”:

  public class ViewOnClickEventHandler: Java.Lang.Object { private List EventList { get; set; } public void SetOnClickEventHandler(View view, EventHandler eventHandler) { if (view.Tag != null) { ViewOnClickEventHandler holder = ((ViewOnClickEventHandler)view.Tag); foreach (EventHandler evH in holder.EventList) view.Click -= evH; for (int i = 0; i < holder.EventList.Count; i++) holder.EventList[i] = null; holder.EventList.Clear(); } EventList = new List(); EventList.Add(eventHandler); view.Click += eventHandler; view.Tag = this; } } 

Puede usarlo en su método ListView BaseAdapter GetItem de esta manera:

  TextView myTextView = convertView.FindViewById(Resource.Id.myTextView); ViewOnClickEventHandler onClick = new ViewOnClickEventHandler(); onClick.SetOnClickEventHandler(myTextView, new EventHandler(delegate (object sender, EventArgs e) { // Do whatever you want with the click event })); 

La clase ViewOnClickEventHandler se ocupará de múltiples eventos en su vista de texto. También puede cambiar la clase para eventos de cambio de texto. Es el mismo principio. Espero que esto sea de ayuda.

adios, nxexo007

Como puede ver aquí: CodeSearch de TextView no hay forma de eliminar a todos los oyentes. La única forma es proporcionarle al observador que utilizó para registrarlo.

Todavía no entiendo completamente por qué hay otros oyentes ya registrados. Sin embargo, puede subclasificar EditText, anular addTextChangedListener (..) y guardar una copia de todas las referencias agregadas y luego delegar en la implementación de la superclase. También puede proporcionar un método adicional que elimine a todos los oyentes.

Póngase en contacto si necesita más explicaciones.