3

我正在寻找一种解决方案来加快更新我的微调器。目前,每当我根据先前选择的微调器更改搜索条件时,我正在使用 SimpleCursorAdapter 并调用 ChangeCursor。

我做了一些时间测试,查询需要 5ms 到 60ms,而 changeCursor 函数需要 600ms 到 4000ms+。是否有另一种方法可以更快地更新适配器上的光标?我没有使用相同的查询,所以我不能简单地重新查询游标,然后调用 notifydatasetchanged。我必须创建一个新查询然后取回一个新光标(也许有更好的方法来完成这部分)。

这是我目前的填充方式

private void writerSpinner() {
        String[] columns = new String[] { Passage.COL_WRITER_ID + " " + BaseColumns._ID, Passage.COL_WRITER_NAME };
        String whereClause = null;
        String groupBy = null;
        String orderBy = Passage.COL_WRITER_ID + " ASC";

        if (mAdapterPassage == null) {
            String[] columnsSpinner = new String[] { Passage.COL_WRITER_NAME };
            int[] to = new int[] { android.R.id.text1 };

            mAdapterPassage = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_spinner_item, null, columnsSpinner, to);
            mAdapterPassage.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            mPassage.setAdapter(mAdapterPassage);
            mPassage.setOnItemSelectedListener(onItemSelectedListener);
        }

        AsyncLoadData loadData = new AsyncLoadData(mAdapterPassage, mPassage, Passage.TABLE_NAME_WRITERS, columns, whereClause, groupBy, orderBy);
        loadData.execute();
    }

    private void updateChapterSpinner() {
        String[] columns = new String[] { Passage.COL_WRITER_ID + " " + BaseColumns._ID, Passage.COL_CHAPTER_ID };
        String whereClause = Passage.COL_WRITER_ID + " = " + mSelectedWriterId;
        String groupBy = Passage.COL_CHAPTER_ID;
        String orderBy = Passage.COL_CHAPTER_ID + " ASC";

        if (mAdapterChapter == null) {
            String[] columnsSpinner = new String[] { Passage.COL_CHAPTER_ID };
            int[] to = new int[] { android.R.id.text1 };

            mAdapterChapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_spinner_item, null, columnsSpinner, to);
            mAdapterChapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            mChapter.setAdapter(mAdapterChapter);
            mChapter.setOnItemSelectedListener(onItemSelectedListener);
        }

        AsyncLoadData loadData = new AsyncLoadData(mAdapterChapter, mChapter, Passage.TABLE_NAME_PASSAGES, columns, whereClause, groupBy, orderBy);
        loadData.execute();
    }

    private void updateVerseSpinner() {
        String[] columns = new String[] { Passage.COL_WRITER_ID + " " + BaseColumns._ID, Passage.COL_VERSE_ID };
        String whereClause = Passage.COL_WRITER_ID + " = " + mSelectedWriterId
                + " AND " + Passage.COL_CHAPTER_ID + " = " + mSelectedChapter;
        String groupBy = Passage.COL_VERSE_ID;
        String orderBy = Passage.COL_VERSE_ID + " ASC";


        if (mAdapterVerse == null) {
            String[] columnsSpinner = new String[] { Passage.COL_VERSE_ID };
            int[] to = new int[] { android.R.id.text1 };

            mAdapterVerse = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_spinner_item, null, columnsSpinner, to);
            mAdapterVerse.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            mVerse.setAdapter(mAdapterVerse);
            mVerse.setOnItemSelectedListener(onItemSelectedListener);
        }

        AsyncLoadData loadData = new AsyncLoadData(mAdapterVerse, mVerse, Passage.TABLE_NAME_PASSAGES, columns, whereClause, groupBy, orderBy);
        loadData.execute();
    }

private class AsyncLoadData extends AsyncTask<Void, Void, Void> {
        String mTableName; 
        String[] mColumns;
        String mWhereClause;
        String mGroupBy;
        String mOrderBy;
        Spinner mSpinner;
        Cursor mCursor;
        SimpleCursorAdapter mAdapter;

        public AsyncLoadData(SimpleCursorAdapter adapter, Spinner spinner, String tableName, String[] columns, String whereClause, String groupBy, String orderBy) {
            mAdapter = adapter;
            mSpinner = spinner;
            mTableName = tableName;
            mColumns = columns;
            mWhereClause = whereClause;
            mGroupBy = groupBy;
            mOrderBy = orderBy;
        }


        @Override
        protected void onPreExecute()
        {
            //mSpinner.setVisibility(View.GONE);
        }

        @Override
        protected Void doInBackground(Void... arg0) {
            long startCursor = new Date().getTime();
            mCursor = mDBHandler.query(mTableName, mColumns, mWhereClause, null, mGroupBy, null, mOrderBy);
            long timeToQuery = new Date().getTime() - startCursor;          

            Log.i("CursorQuery", "Time to Query Cursor " + mGroupBy + ": "  + timeToQuery + "ms");

            return null;
        }

        @Override
        protected void onPostExecute(Void result)
        {   
            long startAdapter = new Date().getTime();
            mAdapter.changeCursor(mCursor);
            long timeToChangeCursor = new Date().getTime() - startAdapter;

            Log.i("AdapterQuery", "Time to Change Cursor " + mGroupBy + ": " + timeToChangeCursor + "ms");

            mAdapter.notifyDataSetChanged();
            //mSpinner.setVisibility(View.VISIBLE);
        }
    }

private OnItemSelectedListener onItemSelectedListener = new OnItemSelectedListener() {

        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            switch(parent.getId()) {
            case R.id.bible_passage:
                mSelectedWriterId = position + 1;
                updateChapterSpinner();
                break;
            case R.id.bible_chapter:
                mSelectedChapter = position + 1;    
                updateVerseSpinner();
                break;
            case R.id.bible_verse:
                mSelectedVerse = position + 1;
                break;
            }
        }

        public void onNothingSelected(AdapterView<?> parent) {

        }
    };
4

1 回答 1

3

问题

changeCursor需要这么长时间 的原因是返回的游标Database.query(...)仅在必要时才初始化(所以这是游标的错,而不是适配器的错)。

游标初始化缓慢的原因是它一次解析整个结果集(因为它需要知道总计数)。尽管 SQLite 非常快地返回大量查询,但 java 解析它们的速度非常慢(比 SQLite 慢 100 到 1000 倍)。

解决方案

进来吧,HugeSQLiteCursor带有 JavaDoc!)。我写了这个游标来解决这个问题。它以增量和自动的方式加载结果,而不是一次全部加载(通过一种巧妙的解决方法来找出几乎 0 开销的总计数)。

下载.jar文件,将其添加到您的libs/文件夹中,然后执行以下操作来使用它(完全限定名称是com.malabarba.hugesqlitecursor.HugeSQLiteCursor):

adapter.changeCursor(new HugeSQLiteCursor(db, stepSize,
                                          table, columnFields,
                                          selection, selectionArgs));

如您所见,由于结果是延迟加载的,因此您需要将数据库和查询参数传递给构造函数。一旦创建,游标应该在您以前使用 SQLiteCursor 的任何情况下都能正常工作。

第二个参数 ( stepSize) 是您希望在创建光标时最初加载的项目数。这是重要的参数

整个游标的初始化时间将与只有stepSize结果一样有效。但是不要使stepSize适合一个屏幕的结果数量更小。

这个 Cursor 有效地消除了“Java 太慢”的瓶颈。在我的 Nexus 4 上,它在不到60 毫秒的时间内返回 50.000 个结果的查询,而 SQLiteCursor 则需要大约 1000 毫秒。当然,如果您的查询非常庞大,以至于 SQLite 返回结果的速度都很慢,那么这个游标只能让您走这么远。

于 2013-09-03T23:31:55.930 回答