我试图在Android应用程序中实现搜索功能,该功能从AutoCompleteTextView
中获取文本,等待最近1.5秒内没有发生变化并显示搜索结果。为此我使用TextWatcher
类。等待完成没有UI冻结的计算
但是,我所有的实现这种行为的尝试都遇到了一些问题,只能通过UI线程本身(通过runOnUIThread
)或调用Looper.prepare()
之前调用某些函数。
在所有尝试中,应用程序在输入其他字符或删除一些内容时随机崩溃,不显示任何搜索结果或重新加载到开始活动。
以下是我最近一次尝试的简单娱乐,我使用的是Handler
。
search.getResults
是很长的计算和matches
是具有待填充delayableAdapterCreation
创建ArrayAdapterWithSpaceFilter
之前的阵列。
public class SearchFragment extends Fragment {
public final static int MAX_NUMBER_OF_SUGGESTIONS = 4; // only show a max of 4 suggestions if more were found
public final static int SEARCH_CHAR_AMOUNT = 3; // only search if at least 3 characters were typed
public final static long SEARCH_DELAY_MILLIS = (long) 1500; // the time to wait for no text changes in milliseconds
private Search search;
private AutoCompleteTextView textView;
private String[] matches;
private String userStartRequest;
private Entry[] suggestions;
private FragmentListenter sListener;
private EntryFunctions ef = new EntryFunctions();
private Runnable delayableSearch;
private Runnable delayableAdapterCreation;
private Handler delayableSearchHandler;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
delayableSearchHandler = new Handler();
delayableSearch = new Runnable() {
@Override
public void run() {
userStartRequest = textView.getText().toString();
sListener.onFragmentFinish(userStartRequest);
suggestions = search.getResults(userStartRequest);
matches = ef.fillMatches(suggestions);
}
};
delayableAdapterCreation = new Runnable() {
@Override
public void run() {
ArrayAdapterWithSpaceFilter<String> adapter =
new ArrayAdapterWithSpaceFilter<String>(getActivity(),
android.R.layout.simple_list_item_1,
matches);
textView.setAdapter(adapter);
}
};
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_search, container, false);
}
@Override
public void onStart() {
super.onStart();
textViewHandler();
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (!(context instanceof FragmentListenter)) throw new AssertionError();
sListener = (FragmentListenter) context;
}
/**
* Interface for communicate to activity
*/
public interface FragmentListenter {
void onFragmentFinish(String userStartRequest);
}
/**
* Handler for the AutoCompleteTextView
*/
private void textViewHandler() {
try {
textView = (AutoCompleteTextView) getView().findViewById
(R.id.startNaviAutoCompleteTextView);
search = new Search();
System.out.println("Created Search object");
textView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
System.out.println("TextWatcher beforeTextChanged");
}
@Override
public void onTextChanged(CharSequence s, final int start, int before, int count) {
delayableSearchHandler.removeCallbacks(delayableSearch); userStartRequest = textView.getText().toString();
sListener.onFragmentFinish(userStartRequest);
if (textView.getText().length() >=
SEARCH_CHAR_AMOUNT) {
new Thread(delayableSearch).start();
delayableSearchHandler.postDelayed
(delayableAdapterCreation, SEARCH_DELAY_MILLIS);
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
在这一点上,它并不重要,我,是否已经开始计算,每当有新的字符键入到AutoCompleteTextView
和最终的旧的搜索被取消或在1.5秒后开始搜索。
如果搜索词不会产生结果并且结果列表出现问题,则上述代码确实会崩溃。有时它会显示前几次按键输入的内容(所以如果我慢慢搜索abcd,我会得到abc的搜索结果),有时它根本不会显示。我的猜测是多次调用textViewHandler
或onTextChanged
方法的竞态条件或一些问题,即使delayableSearchHandler.removeCallbacks(delayableSearch)
应该防止发生这种情况。
任何人都可以解释,工作线程和UI线程之间的交互将不得不看起来像,所以它可以保证搜索提供它的结果?
由于提前,
乔
我很抱歉,我的问题作出的声音misunderstandable。代码的当前状态不会崩溃(只发生在很多先前的尝试中)。这个只是不会立即显示任何搜索结果,但是当我让计算运行延迟时间,然后向它添加另一个字母或删除一个时,它们会显示它们。我认为确切的错误是无关紧要的,因为一旦UI和工作线程之间的通信和调用发生作用,它应该是自我修复的。 –
我不认为我会跟随。你的代码是否会产生不良结果?还是在特定情况下崩溃? –
期望的结果是,在1.5秒后(或者如果搜索本身花费更长时间,则会更长),UI上会显示可能匹配的列表。在这个显示的代码中,列表感觉像随机出现。有时它会显示前几次按键输入的内容(所以如果我慢慢搜索abcd,我会得到abc的搜索结果),有时它根本不会显示。在搜索栏的第一个实现中,我们只是在每个添加的字符之后进行计算,冻结UI,完成时显示结果,然后让用户键入另一个字母。这太慢了。 –