0

我有一个 Java 程序,我刚刚把它变成了一个 slooooooow-to-load Android 应用程序。问题:它处理一个 140,000 字的“字典”(存储在一个Asset文件中),在其中查找匹配“Windows 通配符”模式的单词:例如,S???CK* 将匹配 STICKS、SHACK、STACK、...、STACKOVERFLOW等。在 Windows 7 中速度非常快。在手机上则不然。

我所做的一件事是将所有 140,000 个单词读入一个ArrayList(我对它编译并运行感到震惊),之后,只要该模式不以通配符开头,Collections.binarySearch(...)就可以立即进行查找。

但是将它读入数组列表需要 60 秒,并且用户输入被阻止。并且每次onCreate都必须运行它——即,不可接受的经常发生。

我想加快速度。

这是一个SSCCE完美但太慢的方法:

MainActivity.java

public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    FragmentTransaction
        ft;
        ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.layout_container, new OutputFragment());
        ft.commit();
  };
}

OutputFragment.java

public class          OutputFragment          extends Fragment
{
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
  }

  @Override
  public View onCreateView(LayoutInflater _layoutInflater,
                           ViewGroup      _sourceOfLayoutParams,
                           Bundle         savedInstanceState)
  {


    View v = _layoutInflater.inflate(R.layout.fragment_output,_sourceOfLayoutParams, false);

    EditText et = (EditText)v.findViewById(R.id.txaOutput);

    Matcher matcher = new Matcher(getActivity().getAssets());

    for (int i = 0; i < 9; i++)
       et.append("\n" + matcher.get(i));

   return v;
  }
} 

Matcher.java

public class Matcher extends ArrayList<String> {

  Matcher(AssetManager assets) {

    Scanner scDict = null;
    try { scDict = new Scanner(assets.open("dictionary.dic")); }
    catch (IOException e) { e.printStackTrace(); }

    int k = 0;

    while(scDict.hasNext())// && ++k<10)
      add(scDict.next());
  }
}

activity_main.xml

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width    ="match_parent"
          android:layout_height   ="match_parent"

    xmlns:tools  ="http://schemas.android.com/tools"
          tools:context           =".MainActivity"
    >

   <LinearLayout
       android:id           ="@+id/layout_container"
       android:orientation  ="vertical"
       android:layout_width ="match_parent"
       android:layout_height="match_parent">
   </LinearLayout>

</RelativeLayout>

fragment_output.xml

<GridLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width ="match_parent"
            android:layout_height="match_parent"
      android:rowCount="33"
      android:columnCount="2">

    <TextView
        android:id              ="@+id/txvOutput"
        android:text            ="Output shown below"
        android:layout_width    ="wrap_content"
        android:layout_height   ="wrap_content"
        android:textAppearance  ="?android:attr/textAppearanceLarge"
        android:layout_row="0"
        android:layout_column="0">
    </TextView>

        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="New Text"
            android:id="@+id/txaOutput"
            android:layout_row="2"
            android:inputType="textMultiLine"
            android:layout_column="0"
            android:maxLines="100"/>


</GridLayout>

所以我想要的是加快速度。我已阅读“让您的 Android 应用程序保持响应”。不知道能不能适应我的情况。我从那里举了一个例子,并尽我所能调整它:

  private class LoadWords extends AsyncTask<Scanner, Integer, Long> 
  {
    @Override
    protected Long doInBackground(Scanner... params) { // variable arg list required (??)
      while(params[0].hasNext()) //// no way this could work...
        add(params[0].next());
      return 0L;
    };
  }

我没想到它一输入就可以工作,params[0].hasNext()但似乎需要一个变量参数列表。

这是我尝试实现它的方法:

    LoadWords loadWords = new LoadWords(); /////////////////////////

    InputStream stream = null;
    Scanner     scDict = null;
    ...
                stream = assets.open("dictionary.dic");
    ...    

    scDict = new Scanner(stream);

    loadWords.execute(scDict); ///////////////////// What should I pass?????

我想我应该放弃这种方法并尝试使用Thread我必须管理的方法。我对此感到不舒服。

欢迎任何有关如何进行的建议。

4

2 回答 2

0

由于 Paulo Avelar 提到index,我最终放弃了 Selvin 和 Ed George 的建议,使用 aSQLite database而不是将所有 140,000 个单词全部加载到内存中,我从不认为这是一个好主意,但它足够好用了。但事实证明非常糟糕。

有了数据库,改进是显着的。

通过使用where是用户的模式,索引唯一的列(即,不是过度杀伤)使通配符搜索瞬间完成。"where word like ?""?"

将 140,000 个单词加载到数据库中需要一分钟(一次性任务,假设应用程序的数据未通过 清除Settings),但它正在使用database.beginTransactionendTransaction这使得加载速度足够快。有关详细信息,请参阅此

于 2015-09-20T13:17:03.520 回答
0

我有一个部分解决方案,使用AsyncTask. 在后台加载 140,000 个单词;GUI 立即响应,但并非所有单词都及时加载以返回所有匹配项。

public class ListMaker extends ArrayList<String> 
{
  Scanner scDict;
  InputStream stream = null;

  public Matcher(AssetManager assets) 
  {
    LoadWords loadWords = new LoadWords();
    stream = assets.open("dictionary.dic");
    loadWords.execute((Object[]) null);
  }

  private class LoadWords extends AsyncTask<Object, Integer, ArrayList<String>> {
    @Override
    protected ArrayList<String> doInBackground(Object... params) 
    {
      scDict = new Scanner(stream).useDelimiter("\r\n");
      while (scDict.hasNext())
        add(scDict.next());
      return null;
    }

    @Override
    protected void onPostExecute(ArrayList<String> result) {
      MainActivity.setLoaded(true);
    }
于 2015-09-04T20:10:32.933 回答