2017-06-05 35 views
0

我試圖在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的搜索結果),有時它根本不會顯示。我的猜測是多次調用textViewHandleronTextChanged方法的競態條件或一些問題,即使delayableSearchHandler.removeCallbacks(delayableSearch)應該防止發生這種情況。

任何人都可以解釋,工作線程和UI線程之間的交互將不得不看起來像,所以它可以保證搜索提供它的結果?

由於提前,

回答

0

任何長期運行的操作(網絡電話,數據庫搜索...)可能需要很長時間才能執行從而阻塞UI。在冰淇淋三明治之前,這種行爲被android運行時所容忍。

This article可能是一個很好的閱讀

+0

我很抱歉,我的問題作出的聲音misunderstandable。代碼的當前狀態不會崩潰(只發生在很多先前的嘗試中)。這個只是不會立即顯示任何搜索結果,但是當我讓計算運行延遲時間,然後向它添加另一個字母或刪除一個時,它們會顯示它們。我認爲確切的錯誤是無關緊要的,因爲一旦UI和工作線程之間的通信和調用發生作用,它應該是自我修復的。 –

+0

我不認爲我會跟隨。你的代碼是否會產生不良結果?還是在特定情況下崩潰? –

+0

期望的結果是,在1.5秒後(或者如果搜索本身花費更長時間,則會更長),UI上會顯示可能匹配的列表。在這個顯示的代碼中,列表感覺像隨機出現。有時它會顯示前幾次按鍵輸入的內容(所以如果我慢慢搜索abcd,我會得到abc的搜索結果),有時它根本不會顯示。在搜索欄的第一個實現中,我們只是在每個添加的字符之後進行計算,凍結UI,完成時顯示結果,然後讓用戶鍵入另一個字母。這太慢了。 –