我試圖在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,完成時顯示結果,然後讓用戶鍵入另一個字母。這太慢了。 –