2017-03-01 32 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; 
    }