如何删除使用 addTextChangedListener 添加的所有侦听器

发布于 2024-11-14 11:33:11 字数 805 浏览 2 评论 0原文

我有一个 ListView,其中每一行都有一个 EditText 控件。我想向每一行添加一个 TextChangedListener ;一个包含额外数据的数据,表明 EditText 位于哪一行。问题是,当调用 getView 时,会添加多个 TextWatchers;因为 convertView 已经有一个 TextWatcher (并且指向另一行)。

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

MyTextWatcher 是我实现 TextWatcher 的类;并处理文本事件。 CurrentQuestion 让我知道我正在对哪一行进行操作。当我在框中输入时;调用 TextWatcher 的多个实例。

在添加新的之前,有什么方法可以删除 TextWatchers 吗?我看到了 removeTextChangedListener 方法,但这需要传入特定的 TextWatcher,而且我不知道如何获取指向 TextWatcher 的指针code> 已经存在了。

I have a ListView where each row has an EditText control. I want to add a TextChangedListener to each row; one that contains extra data which says which row the EditText was in. The problem is that as getView gets called, multiple TextWatchers are added; because the convertView already having a TextWatcher (and one that points to a different row).

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

MyTextWatcher is my class that implements TextWatcher; and handles the text events. CurrentQuestion lets me know which row I'm acting upon. When I type in the box; multiple instances of TextWatcher are called.

Is there any way to remove the TextWatchers before adding the new one? I see the removeTextChangedListener method, but that requires a specific TextWatcher to be passed in, and I don't know how to get the pointer to the TextWatcher that is already there.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

舟遥客 2024-11-21 11:33:11

无法直接使用当前的 EditText 界面来执行此操作。我看到两种可能的解决方案:

  1. 重新设计您的应用程序,以便您始终知道将哪些 TextWatcher 添加到特定的 EditText 实例中。
  2. 扩展 EditText 并添加清除所有观察者的可能性。

以下是第二种方法的示例 - 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;
        }
    }
}

以下是如何在 xml 布局中使用 ExtendedEditText

<?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>

There is no way to do this using current EditText interface directly. I see two possible solutions:

  1. Redesign your application so you always know what TextWatcher are added to particular EditText instance.
  2. Extend EditText and add possibility to clear all watchers.

Here is an example of second approach - 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;
        }
    }
}

And here is how you can use ExtendedEditText in xml layouts:

<?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>
凹づ凸ル 2024-11-21 11:33:11

您可以从 EditText 中删除 TextWatcher。首先,我建议您将 TextWatcher 声明移到 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
    }
};

之后您将能够设置 TextWather 更简单一些:

editText.addTextChangedListener(yourTextWatcher);

比您可以像这样删除 TextWatcher :

editText.removeTextChangedListener(yourTextWatcher);

并根据需要设置另一个。

You can remove TextWatcher from your EditText. First of all I suggest you to move TextWatcher declaration outside the the 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
    }
};

After that you will be able to set TextWather little bit simpler:

editText.addTextChangedListener(yourTextWatcher);

Than you can remove TextWatcher like this:

editText.removeTextChangedListener(yourTextWatcher);

and set another if you want.

匿名的好友 2024-11-21 11:33:11

我还花了很多时间寻找解决方案,最终在如下标签的帮助下解决了问题。
它将通过从 ConvertView 的标签获取引用来删除以前的 TextWatcher 实例。
它完美地解决了这个问题。
在您的 CustomAdapter 文件中,设置一个新的内部类,如下所示:

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

然后在您重写的 public View getView(intposition, View ConvertView, ViewGroupparent) 方法中实现如下逻辑:

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

然后实现 TextWatcher 类,如下所示:

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

    }
}

它将删除以前的 TextWatcher 实例通过从 ConvertView 的标签获取引用

I also spent a lot of time finding the solution and finally ended up solving with the help of tag like below.
It would remove previous TextWatcher instances by getting references from tag of the convertView.
It perfectly solves the problem.
In your CustomAdapter file, set a new inner class like below:

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

Then in your overrided public View getView(int position, View convertView, ViewGroup parent) method implement the logic like below:

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

Then implement TextWatcher class as below:

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

    }
}

It would remove previous TextWatcher instances by getting references from tag of the convertView

我喜欢麦丽素 2024-11-21 11:33:11

这个问题已经问了很久了,但有人可能会发现这很有用。 Recyclerview 中 TextWatcher 的问题是我们必须确保在视图回收之前将其删除。否则,我们会丢失 TextWatcher 的实例,并且在 OnBindViewHolder() 中调用removeTextChangedListener(textWatcher)只会删除 TextWatcher 的当前实例。

我解决这个问题的方法是在 FocusChangedListener 中添加 TextChangedListener :

editText.setOnFocusChangeListener(new OnFocusChangeListener() {          
public void onFocusChange(View v, boolean hasFocus) {
    if(hasFocus) {
        editText.addTextChangedListener(textWatcher)
    }
    else{
        editText.removeTextChangedListener(textWatcher)
    }
  }
});

这样我确信当 editText 没有焦点时,文本观察器将被删除,并在获得焦点时再次添加。因此,当 recyclerview 被回收时,editText 将删除所有 textChangeListener。

It has been long since this question was asked, but someone might find this useful. The problem with TextWatcher in Recyclerview is that we have to make sure it is removed before the view is recycled. Otherwise, we loss the instance of the TextWatcher, and calling removeTextChangedListener(textWatcher) in the OnBindViewHolder() will only remove the current instance of TextWatcher.

The way I solve this problem is to add the TextChangedListener inside a FocusChangedListener:

editText.setOnFocusChangeListener(new OnFocusChangeListener() {          
public void onFocusChange(View v, boolean hasFocus) {
    if(hasFocus) {
        editText.addTextChangedListener(textWatcher)
    }
    else{
        editText.removeTextChangedListener(textWatcher)
    }
  }
});

This way I am sure when the editText doesn't have focus then the textwatcher is removed, and added again when it has focus. So, when the recyclerview is recycled the editText will have any textChangeListener removed.

情话已封尘 2024-11-21 11:33:11

我在 RecyclerView 中的许多 EditText 中遇到了类似的问题。我通过反思解决了它。在绑定视图之前调用 ReflectionTextWatcher.removeAll(your_edittext)。这段代码找到所有 TextWatchers 并将它们从本地 EditText 的名为“mListeners”的列表中删除。

public class ReflectionTextWatcher {
    public static void removeAll(EditText editText) {
        try {
            Field field = findField("mListeners", editText.getClass());
            if (field != null) {
                field.setAccessible(true);
                ArrayList<TextWatcher> list = (ArrayList<TextWatcher>) field.get(editText); //IllegalAccessException
                if (list != null) {
                    list.clear();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static Field findField(String name, Class<?> type) {
        for (Field declaredField : type.getDeclaredFields()) {
            if (declaredField.getName().equals(name)) {
                return declaredField;
            }
        }
        if (type.getSuperclass() != null) {
            return findField(name, type.getSuperclass());
        }
        return null;
    }
}

我希望,这会对某人有所帮助。

I struggled with a similar problem with a lot of EditTexts in RecyclerView. I solved it by reflection. Call ReflectionTextWatcher.removeAll(your_edittext) before bind views. This piece of code finds all TextWatchers and removes them from the local EditText's list called "mListeners".

public class ReflectionTextWatcher {
    public static void removeAll(EditText editText) {
        try {
            Field field = findField("mListeners", editText.getClass());
            if (field != null) {
                field.setAccessible(true);
                ArrayList<TextWatcher> list = (ArrayList<TextWatcher>) field.get(editText); //IllegalAccessException
                if (list != null) {
                    list.clear();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static Field findField(String name, Class<?> type) {
        for (Field declaredField : type.getDeclaredFields()) {
            if (declaredField.getName().equals(name)) {
                return declaredField;
            }
        }
        if (type.getSuperclass() != null) {
            return findField(name, type.getSuperclass());
        }
        return null;
    }
}

I hope, this will help someone.

紫轩蝶泪 2024-11-21 11:33:11

将当前文本观察器保存在视图保持器中,您可以找到要删除的文本观察器。

Save the current textwatcher in viewholder and you can find the one you want to remove.

怎樣才叫好 2024-11-21 11:33:11

如果像我一样处理 ViewHolder,那么在创建文本观察器时简单地保存对它的引用是没有帮助的。重用后,视图将到达其他一些 ViewHolder,它不会引用旧的文本观察器,因此无法删除它。

就我个人而言,我选择解决像 @inazaruk 这样的问题,尽管将代码更新为 Kotlin + 重命名类以更好地反映其目的。

class EditTextWithRemovableTextWatchers(context: Context?, attrs: AttributeSet?) : TextInputEditText(context, attrs) {

    private val listeners by lazy { mutableListOf<TextWatcher>() }

    override fun addTextChangedListener(watcher: TextWatcher) {
        listeners.add(watcher)
        super.addTextChangedListener(watcher)
    }

    override fun removeTextChangedListener(watcher: TextWatcher) {
        listeners.remove(watcher)
        super.removeTextChangedListener(watcher)
    }

    fun clearTextChangedListeners() {
        for (watcher in listeners) super.removeTextChangedListener(watcher)
        listeners.clear()
    }
}

If one, like me, deals with ViewHolder, then simply saving a reference to a text watcher upon its creation will not help. Upon reuse the view will get to some other ViewHolder which would not have a reference to that old text watcher, thus one won't be able to delete it.

Personally i chose to solve problem like @inazaruk, though updated code to Kotlin + renamed class to better reflect it's purpose.

class EditTextWithRemovableTextWatchers(context: Context?, attrs: AttributeSet?) : TextInputEditText(context, attrs) {

    private val listeners by lazy { mutableListOf<TextWatcher>() }

    override fun addTextChangedListener(watcher: TextWatcher) {
        listeners.add(watcher)
        super.addTextChangedListener(watcher)
    }

    override fun removeTextChangedListener(watcher: TextWatcher) {
        listeners.remove(watcher)
        super.removeTextChangedListener(watcher)
    }

    fun clearTextChangedListeners() {
        for (watcher in listeners) super.removeTextChangedListener(watcher)
        listeners.clear()
    }
}
违心° 2024-11-21 11:33:11

正如您在这里看到的: TextView的CodeSearch没有办法删除所有侦听器。唯一的方法是提供您用来注册它的观察者。

我还不完全明白为什么还有其他听众已经注册。但是,您可以子类化 EditText,重写 addTextChangedListener(..) 并在其中自己保留所有添加的引用的副本,然后委托给超类实现。然后,您还可以提供一个附加方法来删除所有侦听器。

如果您需要进一步的解释,请联系我们。

As you can see here: CodeSearch of TextView there is no way of removing all listeners. The only way is to provide the watcher you used to register it.

I do not yet fully understand why there are other listeners already registered. However you can subclass the EditText, override the addTextChangedListener(..) and in it keep a copy of all added references yourself and then delegate to the superclass implementation. You then can also provide an additional method that removes all listeners.

Get in touch if you need further explanations.

绝不放开 2024-11-21 11:33:11

我在 xamarin/C# 中遇到了同样的问题,我为此编写了一个类来管理 ListView 内的单击事件,其中项目视图将被“回收”:

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

您可以在 ListView BaseAdapter GetItem 方法中以这种方式使用它:

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

ViewOnClickEventHandler 类将关心你的文本视图上的多个事件。您还可以更改 textchange 事件的类。原理是一样的。
我希望这会有所帮助。

再见,
NXEXO007

I had the same problem with xamarin/C# and I wrote for this a class to manage click events inside a ListView where the item view will be "recycled":

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

You can use it in your ListView BaseAdapter GetItem method this way:

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

The ViewOnClickEventHandler class will care about multiple events on your textview. You can also change the class for textchange events. It's the same princip.
I hope this will help.

bye,
nxexo007

悲欢浪云 2024-11-21 11:33:11

我解决了这种情况,没有扩展 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();
}

I resolved this situation without extend TextView class.

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();
}
噩梦成真你也成魔 2024-11-21 11:33:11

我也遇到过类似的问题。我通过在 ArrayList 中保存对 textWatchers 的引用来解决这个问题:

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

I struggled with a similar problem. I solved it by saving references to my textWatchers in an 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));
}
一绘本一梦想 2024-11-21 11:33:11

我在 RecyclerView 项中的 ViewHolder 中使用 EditText 时遇到了问题,并且当 ViewHolder 已绑定,导致调用了先前绑定调用中添加的 TextWatcher,因此,永无休止的循环。

唯一可行的解​​决方案是存储 TextWatcher > 在列表中,然后在onBindViewHolder,遍历该列表并从 EditText 中删除 TextWatcher

private val textWatchers: MutableList<TextWatcher> = mutableListOf()

在将 TextWatcher 分配给 EditText 之前将其添加到列表:

textWatchers.add(textWatcher1)
vh.moneyAmount.editText?.addTextChangedListener(textWatcher1)

绑定项目时删除它们,将遍历整个 textWatcherList

private fun removeTextWatcher(vh: MoneyItemViewHolder) {
    textWatchers.forEach { vh.moneyAmount.editText?.removeTextChangedListener(it) }
}

没有任何除了传递 TextWatcher 对象之外,还有一种从 EditText 中删除 TextWatcher 的方法,因此它需要存储在我们计划删除的某个地方稍后再说。

I've run into the issue when using EditText in ViewHolder in RecyclerView item, and it was causing error of infinite loop, when ViewHolder was binding, cause the TextWatcher added in previous bind call was called, hence, never-ending loop..

The only working solution for that was to store TextWatcher's in the list, and then in onBindViewHolder, go trough that list and remove TextWatcher from the EditText.

private val textWatchers: MutableList<TextWatcher> = mutableListOf()

Add TextWatcher to list before assigning it to EditText:

textWatchers.add(textWatcher1)
vh.moneyAmount.editText?.addTextChangedListener(textWatcher1)

Remove them when binding the item, going to trough the entire textWatcherList:

private fun removeTextWatcher(vh: MoneyItemViewHolder) {
    textWatchers.forEach { vh.moneyAmount.editText?.removeTextChangedListener(it) }
}

There isn't any other way to remove the TextWatcher's from EditText, than passing the TextWatcher object, hence it needs to be stored somewhere is we plan to remove it later.

一身骄傲 2024-11-21 11:33:11

我删除文本观察者所做的事情非常简单。我创建了一个数组来放置我的文本观察器:

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

我将它们添加到:

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

我的 returnTextWatcherCheckPIN 方法在 afterTextChanged 上使用不同的检查器( switchMethod 来检查所有四个 editTexts)实例化一个文本观察器。

然后,每当我删除文本观察器时,我只是引用数组中的文本观察器:

etPin4.removeTextChangedListener(textWatchers[CURRENT_PIN_CHECK]);

在调试时检查 editText 的侦听器大小:

在此处输入图像描述

已删除!这解决了我的问题!

What I did to remove text watchers is very simple. I created an array to put my textwatchers:

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

I added them in:

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

My returnTextWatcherCheckPIN method instantiates a textWatcher with a different checker (switchMethod to check all four editTexts) on afterTextChanged.

Then whenever I remove a text watcher I just referenced the one from the array:

etPin4.removeTextChangedListener(textWatchers[CURRENT_PIN_CHECK]);

Check the listeners size of the editText on debug:

enter image description here

It's removed! That solved my problem!

风吹过旳痕迹 2024-11-21 11:33:11

为什么不使用 setTag()TextWatcher 引用附加到 EditText 本身?

if (etTagValue.getTag(R.id.textWatcherTag) != null) {
    etTagValue.removeTextChangedListener((TextWatcher) etTagValue.getTag());
}

etTagValue.setText(myValue);
TextWatcher textWatcher = new DelayedTextWatcher(text -> meta.setDescription(text.toString()));
etTagValue.addTextChangedListener(textWatcher);
etTagValue.setTag(R.id.textWatcherTag, textWatcher);

/values 包下的 ids.xml 中:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="textWatcherTag" type="id" />
</resources>

Why not attach the TextWatcher reference to the EditText itself with setTag()?

if (etTagValue.getTag(R.id.textWatcherTag) != null) {
    etTagValue.removeTextChangedListener((TextWatcher) etTagValue.getTag());
}

etTagValue.setText(myValue);
TextWatcher textWatcher = new DelayedTextWatcher(text -> meta.setDescription(text.toString()));
etTagValue.addTextChangedListener(textWatcher);
etTagValue.setTag(R.id.textWatcherTag, textWatcher);

In ids.xml under /values package:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="textWatcherTag" type="id" />
</resources>
月竹挽风 2024-11-21 11:33:11

因为我是使用 notifiDataSetChange 时在适配器中面临 EditText doOnTextChanged 侦听器多个侦听器问题的人之一。经过大量研究和尝试多种方法后,我在@Davi 给出的答案部分找到了解决方案。
现在,我在 @Davi 先生的回答之上制作了一个 Kotlin 内联 函数,以便更轻松地使用。希望它会对你们有所帮助

inline fun EditText.doAfterTextChangedMultipleListenerFix(
   crossinline afterTextChanged: (text: Editable?) -> Unit
) {

   val textWatcher = object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {
        afterTextChanged.invoke(s)
    }

    override fun beforeTextChanged(text: CharSequence?, start: Int, 
        count: Int, after: Int) {
    }

    override fun onTextChanged(text: CharSequence?, start: Int, before: 
      Int, count: Int) {
    }
}

onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
    if (hasFocus) {
        addTextChangedListener(textWatcher)
    } else {
        removeTextChangedListener(textWatcher)
    }
 }

}

这是您的使用方法

youEditText.doAfterTextChangedMultipleListenerFix{text->
    //do what you want
}

最后在通知更改适配器之前您必须明确焦点

As I'm one of those who face EditText doOnTextChanged listener multiple listener problems in the adapter when using notifiDataSetChange. After so much research and trying lots of ways, I found a solution here in the answer section given by @Davi.
And now I made an Kotlin inline function for more easy way to use, this on top of Mr @Davi s answer. Hope it will help you guys

inline fun EditText.doAfterTextChangedMultipleListenerFix(
   crossinline afterTextChanged: (text: Editable?) -> Unit
) {

   val textWatcher = object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {
        afterTextChanged.invoke(s)
    }

    override fun beforeTextChanged(text: CharSequence?, start: Int, 
        count: Int, after: Int) {
    }

    override fun onTextChanged(text: CharSequence?, start: Int, before: 
      Int, count: Int) {
    }
}

onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
    if (hasFocus) {
        addTextChangedListener(textWatcher)
    } else {
        removeTextChangedListener(textWatcher)
    }
 }

}

Here's how you use

youEditText.doAfterTextChangedMultipleListenerFix{text->
    //do what you want
}

And finally you must clear focus before notifi change adapter

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文