2013-01-10 106 views
3

我正在尋找一種解決方案來加速更新我的spinners。目前,我正在使用SimpleCursorAdapter,每當更改基於先前選定的微調器的搜索條件時調用ChangeCursor。Android - 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) { 

     } 
    }; 
+0

刪除'mAdapter.notifyDataSetChanged();'行,因爲'changeCursor()'方法在其實現中調用'notifyDataSetChanged()',因此它是無用的。你確定你得到這些加載值?嘗試使用traceview來查看問題出在哪裏。 – Luksprog

+0

@Luksprog對不起,在代碼中沒有問題,它都按預期運行。它不是很快。 changecursor需要1/2到4秒的時間來更改我的遊標適配器中的數據,這是不可取的。我正在尋找更快的解決方案。 – DMCApps

+0

我並不是說代碼不正確(但該行無用)。我沒有看到另一種方法來更新'Cursor'('swapCursor',但不應該有區別)。使用traceview查看瓶頸在哪裏。此外值得一提的是,如果您僅在某些API級別上測試並看到此問題,或者它是一般性的。 – Luksprog

回答

3

的問題

原因changeCursor需要很長時間的是,當有必要通過 Database.query(...)返回光標僅初始化(所以它的 光標的錯,而不是適配器)。

光標初始化緩慢的原因是它一次解析整個結果集(因爲它需要知道總數)。 雖然SQLite真的很快返回巨大的查詢,但java解析它們的速度非常慢(比SQLite慢100到1000倍)。

進來,HugeSQLiteCursorwith JavaDoc!)。 我寫了這個光標來解決這個問題。它會逐步和自動地加載結果 ,而不是一次全部(使用巧妙的 變通辦法找出接近0開銷的總計數)。

Download the .jar file, 其添加到您libs/文件夾,並做一些類似下面的 使用(完全合格的名稱是com.malabarba.hugesqlitecursor.HugeSQLiteCursor):

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

正如你所看到的,因爲結果加載懶洋洋地,你需要將 傳遞給構造函數的數據庫和查詢參數。 一旦創建完成,光標應該在您以前使用SQLiteCursor的任何情況下都能正常工作。

第二個參數(stepSize)是您希望在創建遊標時最初加載的項目數量 。 這是重要的 參數

整個遊標的初始化時間實際上是 ,就好像它只有stepSize結果一樣。但是,請不要讓stepSize小於適合一個屏幕的結果數量。

這個Cursor有效地消除了「Java太慢」的瓶頸。 在我的Nexus 4上,它返回的查詢結果小於60ms,與SQLiteCursor相比,它耗時約1000ms。 當然,如果你的查詢是如此巨大以至於即使SQLite返回結果的速度很慢,那麼這個遊標也只會讓你滿意。