我有一个Activity,其中用户键入EditText,点击搜索按钮,应用程序查询Web服务并将结果放在ListView中.
我想取消搜索按钮.
显然,我不希望用户输入的每个字符都能访问Web服务.我想只在用户输入完成后执行1个Web服务调用.
我实现这一点的方式是这样的:
我有一个成员变量,它包含一个AsyncTask.当EditText中的文本发生更改时,AsyncTask将触发.在doInBackground()内部,调用Thread.sleep().这个休眠期基本上是一个等待查看用户是否输入任何其他内容的计时器.在睡眠调用之后,如果尚未取消AsyncTask,则会调用Web服务.如果用户键入另一个字母,则在AsyncTask上调用cancel()(以阻止调用Web服务),将保存AsyncTask的成员变量设置为null,并创建AsyncTask的新实例.
我在这里有几个问题:我是否泄漏记忆?这在任何方面都特别糟糕吗?我知道它可能效率不高,但我是否会严重减慢某人的电话速度?有没有更好的方法呢?
private SearchTask mSearchTask = null;
…
mSearchText.addTextChangedListener(new TextWatcher() { public void onTextChanged(CharSequence s,int start,int before,int count) { // Auto-generated method stub } public void beforeTextChanged(CharSequence s,int count,int after) { // Auto-generated method stub } public void afterTextChanged(Editable s) { if (s != null && s.length() > 0) { // stop any current search thread if (mSearchTask != null && !mSearchTask.isCancelled()) { mSearchTask.cancel(false); } // search for products SearchCriteria crit = new SearchCriteria(); crit.strSearchWord = mSearchText.getText().toString().trim(); mSearchTask = null; mSearchTask = new SearchTask(); mSearchTask.execute(crit); } } });
…
private class SearchTask extends AsyncTask<SearchCriteria,Integer,Boolean> { protected Boolean doInBackground(SearchCriteria... params) { SearchCriteria crit = null; if (params.length > 0) { crit = params[0]; if (crit != null) { try { Thread.sleep(1000L); if (!isCancelled()) { // perform search return true; } } catch(Exception e) { } } } return false; } protected void onPostExecute(Boolean success) { if (success != null && success == true) { // do something } else { // do something else } } }
解决方法
我会更愿意在x毫秒内启动一个线程然后进行检查,而不是立即启动线程并在那里进行休眠.
private Handler mMessageHandler = new Handler(); private Runnable mSearchRunnable = new Runnable() { public void run() { if (!isCancelled()) { // perform search } } };
那么你可以在AfterTextChanged后把它放在你身上:
mMessageHandler.postDelayed(mSearchRunnable,1000);
然后,如果用户输入更多数据,您可以取消该线程:
mMessageHandler.removeCallbacks(mSearchRunnable);