2013-01-10 1 views
3

내 스피너 업데이트 속도를 높이는 해결책을 찾고 있습니다. 현재 SimpleCursorAdapter를 사용하고 이전에 선택한 스피너를 기반으로 검색 조건을 변경할 때마다 ChangeCursor를 호출합니다.Android - SimpleCursorAdapter changeCursor function too slow

나는 changeCursor 함수가 600ms에서 4000ms + 사이에 걸리는 반면 약간의 타이밍 테스트를 수행했으며 쿼리는 5ms에서 60ms까지 걸렸다. 더 빠른 어댑터에서 커서를 업데이트하는 다른 방법이 있습니까? 동일한 쿼리를 사용하지 않기 때문에 단순히 커서를 쿼리하고 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

'changeCursor()'메소드가 구현시'notifyDataSetChanged()'를 호출하기 때문에'mAdapter.notifyDataSetChanged();'라인을 쓸모 없게 제거하십시오. 로드 값을 가져 왔습니까? traceview를 사용하여 문제가있는 곳을 확인하십시오. – Luksprog

+0

@Luksprog 죄송합니다. 코드 내에 문제가 없으므로 모든 기능이 의도 된대로 작동합니다. 그것은 매우 빠르지 않다. chang 커서는 커서 어댑터의 데이터를 변경하는 데 1 ~ 2 초에서 4 초 정도 걸리므로 바람직하지 않습니다. 나는 더 빠른 해결책을 찾고있다. – DMCApps

+0

코드가 올바르지 않다고 말하지 않았습니다 (그러나 그 행은 쓸모가 없습니다). 나는'Cursor' ('swapCursor')를 업데이트하는 다른 방법을 보지 못합니다. 그러나 차이는 없어야합니다. traceview를 사용하여 병목 현상이 어디인지 확인하십시오. 또한 특정 API 레벨에서만이 문제를 테스트하고 본 적이 있다면 언급 할만한 가치가 있습니다. – Luksprog

답변

3

을 채우는 오전 방법은 다음과

이다

changeCursor이 너무 오래 걸리는 이유는 필요할 때 Database.query(...)에 의해 반환되는 커서는 초기화 (그래서 커서의 잘못이다 어댑터가 아닌). 커서가 초기화 할 수 느린

이유는 (은 총 수를 알 필요가 있기 때문에)는 한 번에 설정 한 전체 결과를 구문 분석하는 것입니다. SQLite는 거대한 쿼리를 매우 빠르게 반환하지만, java는 매우 느려서 (100-1000 배 느린 SQLite) 구문 분석을 수행합니다.

솔루션

가 와서, HugeSQLiteCursor (with 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을 하나의 화면에 들어 맞는 결과 수보다 작게 만들지 마십시오.

이 커서는 "Java가 너무 느림"병목 현상을 효과적으로 제거합니다. Nexus 4에서 ~ 1000ms가 걸렸던 SQLiteCursor와 반대로 60ms 미만의 결과로 50.000 개의 결과를 반환합니다. 물론 쿼리가 너무 거대해서 SQLite조차도 결과를 반환하는 속도가 느리다면이 커서는 현재까지만 표시됩니다.