在Android中CursorAdapter changeCursor bolck ui thread

时间:2013-08-30 03:05:48

标签: android android-cursoradapter

我的程序为我的GridView使用CursorAdapter,并使用AsynTask获取curosr并刷新我的视图。

在task的doinbackgroud中,我在sqlite中执行查询,并获取光标。 在task的onPostExecute中,我使用CursorAdapter.changeCursor通过新数据刷新我的视图。

但ui线程在changeCursor时被阻止,因为游标有太多关于数千行的数据。

光标不使用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类是Cursor。

当info.members有大约2000行时,它会在我的设备中阻止我的ui线程大约四秒钟。 我在工作线程中调用了cursor.getCount(),但它没有帮助。

2 个答案:

答案 0 :(得分:1)

请参阅Using Cursor with ListView adapter for a large amount of data

使用changeCursor时,它调用Cursor.getCount() - “这会强制查询完全执行并计算结果”。

我这样做了 - 在后台线程中准备游标并获取它的长度(从db中提取数据将在这里执行):

stopManagingCursor(cursor);
cursor = dbAdapter.getData(query);
startManagingCursor(cursor);
count = cursor.getCount();
UI线程中的

(onPostExecute)更改光标:

recordsAdapter.changeCursor(cursor);

在这种情况下,更改光标不会冻结UI线程。

答案 1 :(得分: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()方法会阻塞UI的几秒钟。 我所做的就像快速一样简单 我以这种方式简单地改变了查询

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;
}

以这种方式,在调用swapCursor(newCursor)时,在doInBackground而不是主UI中执行完整查询,因为res.getCount()执行此操作:-) 现在交换非常快! 请注意,swapaCursor返回适配器中的oldCursor,你必须关闭它! 希望它有所帮助!