3

スピナーの更新を高速化するための解決策を探しています。現在、SimpleCursorAdapter を使用しており、以前に選択したスピナーに基づいて検索条件を変更するたびに ChangeCursor を呼び出しています。

ちょっとしたタイミング テストを行ったところ、クエリは 5 ミリ秒から 60 ミリ秒かかりましたが、changeCursor 関数は 600 ミリ秒から 4000 ミリ秒以上かかりました。アダプターのカーソルをより速く更新する別の方法はありますか? 同じクエリを使用していないため、単にカーソルを再クエリしてから 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 ( with JavaDoc! )。この問題を解決するために、このカーソルを書きました。一度にすべてではなく、段階的に自動的に結果をロードします (ほぼ 0 のオーバーヘッドで合計カウントを見つける巧妙な回避策を使用します)。

.jarファイルをダウンロードしてフォルダーに追加しlibs/、次のようにして使用します (完全修飾名は ですcom.malabarba.hugesqlitecursor.HugeSQLiteCursor)。

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

ご覧のとおり、結果は遅延ロードされるため、データベースとクエリ パラメータをコンストラクタに渡す必要があります。作成されたカーソルは、以前に SQLiteCursor を使用していたどのような状況でも完全に機能するはずです。

2 番目の引数 ( stepSize) は、カーソルの作成時に最初にロードするアイテムの数です。これは重要なパラメータです。

カーソル全体の初期化時間は、結果のみの場合と事実上同じになりstepSizeます。stepSizeただし、1 画面に収まる結果の数よりも小さくしないでください。

この Cursor は、「Java が遅すぎる」というボトルネックを効果的に解消します。私のNexus 4では、 SQLiteCursorが約1000ミリ秒かかったのとは対照的に、50.000件の結果のクエリが60ミリ秒未満で返されます。もちろん、クエリが非常に巨大で、SQLite でさえ結果を返すのが遅い場合は、このカーソルでは限界があります。

于 2013-09-03T23:31:55.930 に答える