web-dev-qa-db-fra.com

Comment supprimer tous les écouteurs ajoutés avec addTextChangedListener

J'ai un ListView où chaque ligne a un contrôle EditText. Je veux ajouter un TextChangedListener à chaque ligne; une qui contient des données supplémentaires indiquant la rangée dans laquelle se trouvait EditText. Le problème est que, lorsque getView est appelé, plusieurs TextWatchers sont ajoutés; parce que convertView a déjà un TextWatcher (et un autre qui pointe vers une autre ligne).

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

MyTextWatcher est ma classe qui implémente TextWatcher; et gère les événements de texte. CurrentQuestion me permet de savoir sur quelle ligne j'agis. Quand je tape dans la case; Plusieurs instances de TextWatcher sont appelées.

Est-il possible de supprimer TextWatchers avant d'ajouter le nouveau? Je vois la méthode removeTextChangedListener, mais cela nécessite la transmission d’un TextWatcher spécifique et je ne sais pas comment obtenir le pointeur sur le TextWatcher qui est déjà présent.

39
GendoIkari

Il n’ya aucun moyen de le faire en utilisant directement l’interface EditText courante. Je vois deux solutions possibles:

  1. Modifiez votre application pour que vous sachiez toujours à quel TextWatcher sont ajoutés une instance EditText particulière.
  2. Étendez EditText et ajoutez la possibilité d'effacer tous les observateurs.

Voici un exemple de seconde approche - ExtendedEditText:

public class ExtendedEditText extends EditText
{   
    private ArrayList<TextWatcher> 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<TextWatcher>();
        }
        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;
        }
    }
}

Et voici comment vous pouvez utiliser ExtendedEditText dans les mises en page xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:orientation="vertical" 
    Android:layout_width="fill_parent"
    Android:layout_height="fill_parent">

    <ua.inazaruk.HelloWorld.ExtendedEditText 
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content" 
        Android:text="header"
        Android:gravity="center" /> 

</LinearLayout>
34
inazaruk

Vous pouvez supprimer TextWatcher de votre EditText. Tout d'abord, je vous suggère de déplacer la déclaration TextWatcher en dehors du 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
    }
};

Après cela, vous pourrez configurer TextWather un peu plus simple:

editText.addTextChangedListener(yourTextWatcher);

Alors vous pouvez supprimer TextWatcher comme ceci:

editText.removeTextChangedListener(yourTextWatcher);

et en définir un autre si vous voulez.

17
Anton Derevyanko

J'ai aussi passé beaucoup de temps à trouver la solution et finalement j'ai fini par résoudre avec l'aide de tag comme ci-dessous. Cela supprimerait les occurrences précédentes de TextWatcher en récupérant les références de la balise convertView . Il résoudra parfaitement le problème . Dans votre fichier CustomAdapter, définissez une nouvelle classe interne comme ci-dessous:

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;
        }
    }

Ensuite, dans votre méthode View getView publique substituée (position int, View convertView, parent ViewGroup) implémentez la logique comme ci-dessous:

@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);
}

Puis implémentez la classe TextWatcher comme ci-dessous:

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");

    }
}

Cela supprimerait les occurrences précédentes de TextWatcher en obtenant des références à partir de la balise convertView

8
gunjot singh

Enregistrez le textwatcher actuel dans le viewholder et vous pourrez trouver celui que vous voulez supprimer.

6
Lance H

J'ai résolu cette situation sans étendre la classe TextView.

private ArrayList<TextWatcher> mEditTextWatcherList = new ArrayList<>();
private TextWatcher mTextWatcher1;
private TextWathcer mTextWatcher2;

mTextWathcer1 = 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) {}
};

mTextWathcer2 = 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) {}
};

@Override 
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity);

    setListener(mTextWatcher1);
    setListener(mTextWatcher2);

    removeListeners();
}

private setListener(TextWatcher listener) {
    mEditText.addTextChangedListener(listener);
    mEditTextWatcherList.add(listener);
}

private removeListeners() {
    for (TextWatcher t : mEditTextWatcherList)
        mEditText.removeTextChangedListener(t);

    mEditTextWatcherList.clear();
}
1
Luiz Henrique Alegria

J'ai eu le même problème avec xamarin/C # et j'ai écrit pour cela une classe pour gérer les événements de clic dans un ListView où la vue d'élément sera "recyclée":

 public class ViewOnClickEventHandler: Java.Lang.Object
 {
    private List<EventHandler> 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<EventHandler>();
        EventList.Add(eventHandler);
        view.Click += eventHandler;
        view.Tag = this;
    }
}

Vous pouvez l'utiliser dans votre méthode ListView BaseAdapter GetItem de cette façon:

       TextView myTextView = convertView.FindViewById<TextView>(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 classe ViewOnClickEventHandler se préoccupera de plusieurs événements sur votre affichage de texte. Vous pouvez également modifier la classe pour les événements textchange. C'est le même principe ... J'espère que cela aidera.

au revoir, nxexo007

1
nxexo007

Ce que j'ai fait pour supprimer les observateurs de texte est très simple. J'ai créé un tableau pour mettre mes observateurs de texte:

final TextWatcher[] textWatchers = new TextWatcher[3];

Je les ai ajoutés dans:

final int CURRENT_PIN_CHECK = 0, NEW_PIN = 1, CONFIRM_PIN_CHECK = 2;

textWatchers[CURRENT_PIN_CHECK] = returnTextWatcherCheckPIN(CURRENT_PIN_CHECK);
textWatchers[NEW_PIN] = returnTextWatcherCheckPIN(NEW_PIN);
textWatchers[CONFIRM_PIN_CHECK] = returnTextWatcherCheckPIN(CONFIRM_PIN_CHECK);

Ma méthode returnTextWatcherCheckPIN instancie textWatcher avec un vérificateur différent (switchMethod pour vérifier les quatre editTexts) sur afterTextChanged.

Ensuite, chaque fois que je supprime un observateur de texte, je viens de référencer celui du tableau:

etPin4.removeTextChangedListener(textWatchers[CURRENT_PIN_CHECK]);

Vérifiez la taille des auditeurs du editText lors du débogage:

 enter image description here

C'est enlevé! Cela a résolu mon problème!

0
Kim Montano

Comme vous pouvez le voir ici: CodeSearch de TextView il n’ya aucun moyen de supprimer tous les écouteurs. Le seul moyen est de fournir à l'observateur que vous avez utilisé pour l'enregistrer.

Je ne comprends pas encore pourquoi il y a d'autres auditeurs déjà enregistrés. Cependant, vous pouvez sous-classer le EditText, remplacer le addTextChangedListener (..) et y conserver vous-même une copie de toutes les références ajoutées, puis déléguer à la mise en oeuvre de la superclasse. Vous pouvez alors également fournir une méthode supplémentaire qui supprime tous les écouteurs.

Contactez-nous si vous avez besoin d'explications supplémentaires.

0
icyerasor

Je me suis battu avec un problème similaire. Je l'ai résolu en enregistrant les références à mes textWatchers dans une ArrayList:

private final List<TextWatcher> textWatchersForProfileNameTextBox = new ArrayList<>();

public void addTextWatcherToProfileNameTextBox(TextWatcher textWatcher){
    textWatchersForProfileNameTextBox.add(textWatcher);
    getProfileNameTextView().addTextChangedListener(textWatcher);
}

public void removeAllTextWatchersFromProfileNameTextView(){
    while (!textWatchersForProfileNameTextBox.isEmpty())
        getProfileNameTextView().removeTextChangedListener(textWatchersForProfileNameTextBox.remove(0));
}
0
vatbub