2017-06-05 64 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,完成时显示结果,然后让用户键入另一个字母。这太慢了。 –