CursorAdapter changeCursor bolck ui thread в android

Моя программа использует CursorAdapter для моего GridView и использует AsynTask для получения curosr и обновления моего представления.

В задаче doinbackgroud я выполняю запрос в sqlite и получаю курсор. В задаче onPostExecute я использую CursorAdapter.changeCursor для обновления представления новыми данными.

Но поток пользовательского интерфейса был заблокирован при изменении курсора, потому что курсор имеет слишком много данных о тысячах строк.

Разве курсор не использует ленивую стратегию? Как мне поступить?

мой код:

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.nodes является Cursor.

Когда в info.members будет около 2000 строк, он заблокирует мой поток пользовательского интерфейса примерно на четыре секунды на моем устройстве. Я вызываю cursor.getCount() в рабочем потоке, но это не помогает.


person Zebulon Li    schedule 30.08.2013    source источник
comment
Как именно вы пришли к выводу, что использование changeCursor() блокирует поток пользовательского интерфейса?   -  person user    schedule 30.08.2013
comment
во-первых. Он не будет блокировать поток пользовательского интерфейса, когда данных около сотни в курсоре. И когда данных около пяти сотен, он будет блокировать несколько секунд. Но когда данных больше одной тысячи, это вызовет ANR. Во-вторых. Все коды для получения данных находятся в методе doinbackground. А в onPostExecute я мало что делаю, кроме changeCursor().   -  person Zebulon Li    schedule 30.08.2013
comment
@ZebulonLi Зачем вообще вызывать .getCount(), если вы собираетесь игнорировать только возвращаемое значение?   -  person SK9    schedule 24.01.2014
comment
@ SK9 Это всего лишь попытка ответа LionKing ниже.   -  person Zebulon Li    schedule 27.01.2014
comment
Как были получены курсоры dataInfo.members и dataInfo.nodes? Такое впечатление, что курсоры info.members,info.nodes и dataInfo.members,dataInfo.nodes разные. Попробуйте измерить время вызова каждого метода.   -  person LionKing    schedule 30.01.2014
comment
@LionKing Прости. информация на самом деле является dataInfo. Я опускаю некоторый код и делаю ошибку. Копирую сюда способ получения данных курсора.   -  person Zebulon Li    schedule 15.02.2014
comment
@Zebulon Li Попробуйте измерить время вызова каждого метода.   -  person LionKing    schedule 17.02.2014


Ответы (2)


См. Использование курсора с адаптером ListView для большого количества данных

Когда вы используете changeCursor, он вызывает Cursor.getCount() - «это приводит к полному выполнению запроса и подсчету результатов».

Я сделал так - в фоновом потоке подготовьте курсор и получите его длину (здесь будет выполняться извлечение данных из БД):

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

в потоке пользовательского интерфейса (onPostExecute) изменить курсор:

recordsAdapter.changeCursor(cursor);

В этом случае курсор изменения не замораживает поток пользовательского интерфейса.

person LionKing    schedule 20.11.2013
comment
Спасибо за ваш ответ, но это не помогает. Мой телефон Nexus S с 4.1.2. - person Zebulon Li; 23.12.2013

Я знаю, что пост старый, но он может быть полезен для кого-то, я решил свою проблему простым способом :-) Предположим, что мой запрос, который я вызываю из асинтаска в doInBackground, выглядит примерно так:

...
@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), потому что это делает res.getCount() :-) теперь обмен происходит очень быстро! Обратите внимание, что swapaCursor возвращает старыйCursor в адаптере, и вы ДОЛЖНЫ его закрыть! Надеюсь, поможет!

person Pecana    schedule 25.08.2017