安卓EditText:检测用户何时停止编辑

5

我有一个editText,代表搜索条件的输入。我想知道是否有一种方法可以检测用户何时停止编辑此editText,以便我可以查询数据库以获取列表数据。例如,如果用户输入“test”,我只想在用户输入完整单词后被通知,而不是在用户输入每个字母后被通知,就像文本监听器所做的那样。你有什么想法吗?我想避免使用计时器来测量按键事件之间经过的毫秒数。


1
你不能使用空格作为分隔符吗?在TextWatcher中指定正则表达式并验证空格。 - the-ginger-geek
不一定,用户可能没有按下空格键,或者只输入了名字的一半,期望看到可用的结果。 - Buda Gavril
但是接下来你想要使用字符。你想要在用户输入时避免多次请求数据库吗? - the-ginger-geek
是的,我想在用户输入时避免对您的数据库进行多次请求。 - Buda Gavril
我认为你应该添加一个按钮,用户可以点击搜索。任何其他方法都可能会变得混乱并引起问题。 - the-ginger-geek
显示剩余3条评论
5个回答

10

这不是非常优雅,但这应该可以解决问题。

初始化:

long idle_min = 4000; // 4 seconds after user stops typing
long last_text_edit = 0;
Handler h = new Handler();
boolean already_queried = false;

设置可运行的文本监视器,以便从中调用:

private Runnable input_finish_checker = new Runnable() {
    public void run() {
            if (System.currentTimeMillis() > (last_text_edit + idle_min - 500)) {
                 // user hasn't changed the EditText for longer than
                 // the min delay (with half second buffer window)
                 if (!already_queried) { // don't do this stuff twice.
                     already_queried = true;
                     do_stuff();  // your queries
                 }
            }
    }
};

将此代码放入您的文本监视器中:

last_text_edit = System.currentTimeMillis();
h.postDelayed(input_finish_checker, idle_min); 

当我将它放入TextWatcher中时,只需要几个字符,例如当我输入“Hello”时,它只会取“He”。 - Harsh Patel
1
我已经找到了问题的解决方案。实际上,每次它都会创建新的线程,所以我们需要停止早期的线程。为此,我们需要停止早期的线程。这是函数h.removeCallbacks(input_finish_checker)。 - Harsh Patel

7

首先创建以下字段:

private Date                _lastTypeTime   = null;

然后确保你的editText实现了'TextWatcher':
_editText.addTextChangedListener(this);

接下来,按照以下方式覆盖接口的方法:

@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3)
{
    _lastTypeTime = new Date();
}

@Override
public void afterTextChanged(Editable arg0)
{
}

@Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3)
{
    // dispatch after done typing (1 sec after)
    Timer t = new Timer();
    TimerTask tt = new TimerTask()
    {
        @Override
        public void run()
        {
            Date myRunTime = new Date();

            if ((_lastTypeTime.getTime() + 1000) <= myRunTime.getTime())
            {
                post(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        Log.d("<tag>", "typing finished!!!");
                    }
                });
            }
            else
            {
                Log.d("<tag>", "Canceled");
            }
        }
    };

    t.schedule(tt, 1000);
}

非常感谢@gor,这绝对是迄今为止最好的解决方案:D - Mohamed Heiba
回答不错,但我认为您需要视图才能使帖子工作。 - Sotti
1
方法 post 不存在。 - user4400167
“post”方法可通过扩展视图(这是示例情况)或使用处理程序来使用。 - gor

6
这里是如何检测您所需的事件。
声明和初始化:
private Timer timer = new Timer();
private final long DELAY = 1000; // in ms

例如在onCreate()中的监听器

EditText editText = (EditText) findViewById(R.id.editTextStopId);
    editText.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
        }
        @Override
        public void onTextChanged(final CharSequence s, int start, int before,
                int count) {
            if(timer != null)
                timer.cancel();
        }
        @Override
        public void afterTextChanged(final Editable s) {
            //avoid triggering event when text is too short
            if (s.length() >= 3) {              

                timer = new Timer();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        // TODO: do what you need here (refresh list)
                        // you will probably need to use
                        // runOnUiThread(Runnable action) for some specific
                        // actions
                        queryDB();
                    }

                }, DELAY);
            }
        }
    });

所以,当文本被改变时,计时器开始等待下一次变化发生。当它们发生时,计时器被取消,然后再次启动。

这段代码会等待1000毫秒或者其他延迟,但是之后它会运行queryDB()函数和字符数一样多的次数。 - Micro
这怎么可能呢?它只会运行一次,但是在 run() 被触发后写另一个字母的风险将再次触发它。为了应对这种情况,可以暂时禁用输入。 - ZimaXXX
1
我发现如果你快速输入“微型”,系统会等待1000毫秒,然后连续两次运行queryDB()而不延迟。这是我的测试结果,我照字面意思复制了它。在run()方法中放一个日志语句并尝试一下? - Micro

2

这是我所做的,并且对我有用!

long delay = 1000; // 1 seconds after user stops typing
long last_text_edit = 0;
Handler handler = new Handler();

private Runnable input_finish_checker = new Runnable() {
    public void run() {
        if (System.currentTimeMillis() > (last_text_edit + delay - 500)) {
            // TODO: do what you need here
            DoStaff();
        }
    }
};

EditText editText = (EditText) findViewById(R.id.editTextStopId);
editText.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
    }
    @Override
    public void onTextChanged(final CharSequence s, int start, int before,
            int count) {
         //You need to remove this to run only once
         handler.removeCallbacks(input_finish_checker);

    }
    @Override
    public void afterTextChanged(final Editable s) {
        //avoid triggering event when text is empty
        if (s.length() > 0) {              
          last_text_edit = System.currentTimeMillis();
          handler.postDelayed(input_finish_checker, delay);
        } else {

        }
    }
});

0

检查editText是否有文本的最简单方法(仅一次),请执行以下操作:

    private boolean newState;


  protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.somLayout);

    edt.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) {
                    if (!editable.trim().isEmpty()) {
                        checkIsTyping(true);
                    } else {
                        checkIsTyping(false);
                    }
                }
            });

}
    private void checkIsTyping(boolean typeState) {
            if (newState != typeState) {
                Toast.makeText(appCompatActivity, "typingState  " + newState, 
            Toast.LENGTH_SHORT).show();
            }
            newState = typeState;
    
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接