2013-08-30 27 views
1

我的程序在我的GridView中使用CursorAdapter,並使用AsynTask來獲取curosr並刷新我的視圖。CursorAdapter在android中改變遊標bolck ui線程

在任務的doinbackgroud中,我在sqlite中執行查詢,並獲取遊標。 在任務的onPostExecute中,我使用CursorAdapter.changeCursor以新數據刷新我的視圖。

但是當changeCursor因爲光標的數據量過大而導致數千行時ui線程被阻塞。

遊標是否使用lasy策略? 我該怎麼辦?

我的代碼:

private class ToNodeTask extends AsyncTask<Long, Void , OrgManager.CursorDataInfoInStruct >{ 

    protected Long taskId = null; 

    @Override 
    protected OrgManager.CursorDataInfoInStruct doInBackground(Long... params) { 
     taskId = params[0]; 
     OrgManager.CursorDataInfoInStruct info = OrgManager.getInstance().getCursorDataInfoInStruct(taskId); 
     if(info != null){ 
      if(info.members != null){ 
       info.members.getCount(); 
      } 
      if(info.nodes != null){ 
       info.nodes.getCount(); 
      } 
     } 

     return info; 
    } 

    @Override 
    protected void onPostExecute(OrgManager.CursorDataInfoInStruct result) { 
     super.onPostExecute(result); 

     if(result != null){ 

      gridAdapter.changeCursor(result.members); 
      departmentAdapter.changeCursor(result.nodes); 
     } 

    } 

} 

//OrgManager.java

public CursorDataInfoInStruct getCursorDataInfoInStruct(long structId){ 
     OrgStruct struct = getStruct(structId); 
     if(null == struct && structId != 0) return null; 

     CursorDataInfoInStruct info = new CursorDataInfoInStruct(); 
     info.parent = struct; 
     info.nodes = getDb().rawQuery(SQL_QUERY_NODE_DATA_IN_SRUCT, new String[]{String.valueOf(structId)}); 
     info.members = getDb().rawQuery(SQL_QUERY_MEMBER_DATA_IN_SRUCT , new String[]{String.valueOf(structId)}); 

     return info; 
    } 

info.members和info.no​​des的類是光標。

當info.members有大約2000行時,它會在我的設備中阻塞我的UI線程約四秒鐘。 我在工作線程中調用cursor.getCount(),但它沒有幫助。

+0

您是如何得出結論的:使用'changeCursor()'阻止UI線程? – Luksprog

+0

首先,當遊標中的數據大約有一百個時,它不會阻塞ui線程。而當數據大約有五百個時,它會阻塞幾秒。但是當數據超過一千時,就會導致ANR。第二。所有獲取數據的代碼都在doinbackground.and onPostExecute方法中,除了changeCursor()之外,其他所有代碼都可以使用。 –

+0

@ZebulonLi如果你只是忽略返回值,爲什麼要調用'.getCount()'? – SK9

回答

1

Using Cursor with ListView adapter for a large amount of data

當您使用changeCursor它調用Cursor.getCount() - 「這會強制完全執行的查詢和結果計算」。

我這樣做了 - 在後臺線程準備光標並獲得它的長度(從數據庫提取數據,將在這裏執行):

stopManagingCursor(cursor); 
cursor = dbAdapter.getData(query); 
startManagingCursor(cursor); 
count = cursor.getCount(); 

在UI線程(onPostExecute)改變光標:

recordsAdapter.changeCursor(cursor); 

在這種情況下,更改遊標不會凍結UI線程。

+0

感謝您的回覆,但這並沒有幫助。我的手機是帶有4.1.2的Nexus S。 –

+0

請顯示您的示例。 – LionKing

+0

對不起,這種渴望wating.I發佈我的代碼。 –

0

我知道後是舊的,但它可能對某人是有益的, 我解決我的問題,以簡單的方式:-) 假設我的查詢這是我從上doInBackground的調用的AsyncTask是類似的東西:

... 
@Override 
protected Boolean doInBackground(String... aurl) { 
    Cursor newCursor = getALLmyData(); 
    runOnUiThread(new Runnable() { 
     @Override 
     public void run() { 
      final Cursor oldCursor = adapter.swapCursor(newCursor); 
      if(oldCursor!=null){ 
      oldCursor.close(); 
     } 
    } 
    }); 
    .... 

private Cursor getALLmyData() { 
    SQLiteDatabase db = this.getReadableDatabase(); 
    String query = "select * FORM MY_HUGE_TABLE"; 
    return db.rawQuery(query, null, null); 
} 

在這種情況下,adapter.swapCursor(newCursor);由於適配器中的.getCount()方法會阻塞用戶界面數秒。 我所做的很簡單,只要快速 我簡單的以這種方式

public Cursor getALLmyData() { 
    SQLiteDatabase db = this.getReadableDatabase(); 
    String query = "select * FORM MY_HUGE_TABLE"; 
    Cursor res = db.rawQuery(query, null, null); 
    Log.d(TAG," Rows:" +res.getCount()); 
    return res; 
} 
以這種方式,完整的查詢在doInBackground同時呼籲swapCursor(newCursor)主界面的執行,而不是

改變了查詢,因爲水庫.getCount()做到這一點:-) 現在交換速度非常快! 請注意,swapaCursor返回適配器中的oldCursor,並且必須關閉它! 希望它有幫助!