2017-03-01 38 views
1

我正在處理我的Android應用上的InstantSearch功能,我想要的結果是下圖中的一個。使用大陣列列表加速自動完成算法

http://stackoverflow.com/a/30429439/4907138

一切工作正常,除了一兩件事。我使用的ArrayList是BIG(它包含幾乎400k字)。因此,在ListView上顯示我的結果時,我遇到了性能問題(它滯後很多)。

我很確定這是由於我的Wordlist的長度造成的,因爲減少了它的字數,一切都像黃油一樣流暢。

這裏是在適配器類我的過濾代碼:

private class SearchResultsFilter extends Filter { 

    @Override 
    protected FilterResults performFiltering(CharSequence constraint) { 

     FilterResults filterResults = new FilterResults(); 

     ArrayList<String> found = new ArrayList<>(); 
     if (constraint != null) { 
      for (String word : MainActivity.WordList) { 
       if (word.startsWith(constraint.toString().toLowerCase())) { 
        found.add(word); 
       } 
      } 
     } 

     filteredList = found; 
     filterResults.values = found; 
     filterResults.count = found.size(); 

     return filterResults; 
    } 

    @Override 
    protected void publishResults(CharSequence constraint, FilterResults filterResults) { 
     if (filterResults.count > 0) { 
      Log.println(Log.INFO, "Results", "FOUND"); 
      results.clear(); 
      results.addAll((ArrayList<String>) filterResults.values); 
      notifyDataSetChanged(); 
     } else { 
      Log.println(Log.INFO, "Results", "-"); 
      results.clear(); 
      notifyDataSetInvalidated(); 
     } 

    } 
} 

這就是我如何加載我的ArrayList在我MainActivity

public static void loadDictionary(Activity activity) { 
     //loading wordslist from file. 
     BufferedReader line_reader = new BufferedReader(new InputStreamReader(activity.getResources().openRawResource(R.raw.wordlist))); 
     String line; 
     try { 
      while ((line = line_reader.readLine()) != null) { 
       WordList.add(line); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     Collections.sort(WordList); 

謝謝大家,

有無美好的一天。

+0

不顯示自動完成,直到有人類型至少X字母...... X的值發揮到適合您的需求 – Selvin

+0

@Selvin謝謝您的回答。我不認爲這個解決方案解決了我的問題,因爲每次我輸入一個字母時,我的代碼仍然遍歷整個列表。相反,我想知道是否可以使用不同的算法來減少每次檢查的字數。也許它可能會更好地使用不同的數據結構? – Cesarsk

回答

1

我是Cesarsk項目的合作者,我注意到我們的問題是performFiltering方法。我們使用的Wordlist中有394.000多個元素,而且每次用戶在SearchBar的EditText中鍵入一個字母時,performFiltering方法都會檢查它們,即使它在每次迭代時都應該排除某些字母。所以我實現了一個簡單的方法來將列表拆分成不同的子列表。每個列表只包含以字母表中的單個字母開頭的單詞。

含義:

  • 列表1中包含字母開頭的唯一的一句話 「一個
  • 清單2中只包含單詞開始以字母 「b

    等等上...

然後我把所有列表放在一個HashMapkey =字母。做到這一點,現在我們只能選擇與用戶輸入的第一個字母相匹配的子列表,循環會檢查很少的單詞,從而立即生成結果。

下面是一些代碼:

@Override 
    protected FilterResults performFiltering(CharSequence constraint) { 

     FilterResults filterResults = new FilterResults(); 

     ArrayList<Pair<String, String>> temp_list = null; 
     ArrayList<Pair<String, String>> found = new ArrayList<>(); 

     if (constraint != null) { 
      if (!(constraint.toString().isEmpty())) { 
       temp_list = MainActivity.Wordlists_Map.get(constraint.toString().substring(0,1).toLowerCase()); 

       if(temp_list != null){ 
        for(Pair<String, String> element : temp_list){ 
         if(element.first.startsWith(constraint.toString().toLowerCase())){ 
          found.add(element); 
         } 
        } 
       } 
      } 
     } 

     filterResults.values = found; 
     filterResults.count = found.size(); 

     return filterResults; 
    }