Utilizar Cursor con el adaptador ListView para una gran cantidad de datos

Estoy utilizando un CursorAdapter personalizado para obtener datos de una base de datos SQLite y mostrarlo en un listview. La base de datos contiene 2 columnas con alrededor de 8.000 filas. Así que estoy buscando una manera de consultar y mostrar todos los datos lo más rápido posible. He hecho esto con asyncTask aquí es el código:

private class PrepareAdapter extends AsyncTask<Void,Void,CustomCursorAdapter > { @Override protected void onPreExecute() { dialog.setMessage("Wait"); dialog.setIndeterminate(true); dialog.setCancelable(false); dialog.show(); Log.e("TAG","Posle nov mAdapter"); } @Override protected CustomCursorAdapter doInBackground(Void... unused) { Cursor cursor = myDbNamesHelper.getCursorQueryWithAllTheData(); mAdapter.changeCursor(cursor); startManagingCursor(cursor); Log.e("TIME","posle start managing Cursor" + String.valueOf(SystemClock.elapsedRealtime()-testTime)+ " ms"); testTime=SystemClock.elapsedRealtime(); mAdapter.initIndexer(cursor); return mAdapter; } protected void onPostExecute(CustomCursorAdapter result) { TabFirstView.this.getListView().setAdapter(result); Log.e("TIME","posle adapterSet" + String.valueOf(SystemClock.elapsedRealtime()-testTime)+ " ms"); testTime=SystemClock.elapsedRealtime(); dialog.dismiss(); } 

}

Esto funciona bien excepto la parte cuando necesito fijar el resultado en un adaptador. He hecho algunas pruebas del tiempo y tarda aprox 700 ms para hacerla más allá del startManagingCursor. El problema es que se tarda unos 7 segundos en pasar el setAdapter (resultado) y esto se ejecuta en el subproceso de la interfaz de usuario, por lo que hace que mi aplicación no responda (el diálogo de progreso se bloquea y, a veces, la aplicación). ¿Cómo hago este tiempo menos? ¿Puedo hacer que esto también se ejecute en el fondo o cualquier forma de aumentar la capacidad de respuesta?

Txn

 public class CustomCursorAdapter extends SimpleCursorAdapter implements OnClickListener,SectionIndexer,Filterable, android.widget.AdapterView.OnItemClickListener{ private Context context; private int layout; private AlphabetIndexer alphaIndexer; public CustomCursorAdapter (Context context, int layout, Cursor c, String[] from, int[] to) { super(context, layout, c, from, to); this.context = context; this.layout = layout; } public void initIndexer(Cursor c){ alphaIndexer=new AlphabetIndexer(c, c.getColumnIndex(DataBaseNamesHelper.COLUMN_NAME), " ABCDEFGHIJKLMNOPQRSTUVWXYZ"); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { Cursor c = getCursor(); final LayoutInflater inflater = LayoutInflater.from(context); View v = inflater.inflate(layout, parent, false); int nameCol = c.getColumnIndex(DataBaseNamesHelper.COLUMN_NAME); String name = c.getString(nameCol); /** * Next set the name of the entry. */ TextView name_text = (TextView) v.findViewById(R.id.name_entry); if (name_text != null) { name_text.setText(name); } int favCol = c.getColumnIndex(DataBaseNamesHelper.COLUMN_FAVOURITED); int fav = c.getInt(favCol); int idCol = c.getColumnIndex(DataBaseNamesHelper.COLUMN_ID); Button button = (Button) v.findViewById(R.id.Button01); button.setOnClickListener(this); button.setTag(c.getInt(idCol)); if(fav==1){ button.setVisibility(View.INVISIBLE); } else button.setVisibility(View.VISIBLE); return v; } @Override public void bindView(View v, Context context, Cursor c) { int nameCol = c.getColumnIndex(DataBaseNamesHelper.COLUMN_NAME); String name = c.getString(nameCol); /** * Next set the name of the entry. */ TextView name_text = (TextView) v.findViewById(R.id.name_entry); if (name_text != null) { name_text.setText(name); } int favCol = c.getColumnIndex(DataBaseNamesHelper.COLUMN_FAVOURITED); int fav = c.getInt(favCol); Button button = (Button) v.findViewById(R.id.Button01); button.setOnClickListener(this); int idCol = c.getColumnIndex(DataBaseNamesHelper.COLUMN_ID); button.setTag(c.getInt(idCol)); // Log.e("fav",String.valueOf(fav)); if(fav==1){ button.setVisibility(View.INVISIBLE); } else button.setVisibility(View.VISIBLE); } @Override public int getPositionForSection(int section) { return alphaIndexer.getPositionForSection(section); } @Override public int getSectionForPosition(int position) { return alphaIndexer.getSectionForPosition(position); } @Override public Object[] getSections() { return alphaIndexer.getSections(); } @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { Log.e("item Click", arg1.toString()+ " position> " +arg2); } @Override public void onClick(View v) { if(v.getId()==R.id.Button01){ //Log.e("Button Click", v.toString()+ " position> " +v.getTag().toString()); v.setVisibility(View.INVISIBLE); DataBaseNamesHelper dbNames = new DataBaseNamesHelper(context); dbNames.setFavouritesFlag(v.getTag().toString()); } } } 

La razón del tiempo lento en cargar el adaptador es la llamada interna que hace CursorAdapter a Cursor.getCount ().

Los cursores en Android se cargan perezosamente. Los resultados no se cargan hasta que sean necesarios. Cuando el CursorAdapter llama a getCount (), esto obliga a la consulta a ejecutarse completamente ya los resultados contados.

A continuación hay un par de enlaces que discuten este mismo tema.

http://groups.google.com/group/android-developers/browse_thread/thread/c1346ec6e2310c0c

http://www.androidsoftwaredeveloper.com/2010/02/25/sqlite-performance/

Mi sugerencia sería dividir su consulta. Cargue sólo el número de elementos de la lista visible en la pantalla. A medida que el usuario se desplaza, carga el siguiente conjunto. Muy parecido a las aplicaciones de GMail y Market. Desafortunadamente no tengo un ejemplo práctico 🙁

Esto no responde a su pregunta, pero espero que proporciona una idea 🙂

No estoy seguro de por qué setAdapter debe tomar tanto tiempo. He hecho alrededor de 5000 filas mucho más rápido que eso. Sin embargo, por lo general, crear un adaptador sin un cursor primero, llamar a setAdapter con el adaptador "vacío", a continuación, iniciar una consulta asincrónica utilizando una subclase AsyncQueryHandler. Entonces, en onQueryComplete, llamo changeCursor en el adaptador.

Bueno, sólo puedo ofrecerle una sugerencia tonta en este punto – comenzar una consulta en un hilo separado que pasará por toda la base de datos y crear su cursor de 8000 filas.

En el hilo de la interfaz de usuario, cree un cursor en el que establezca el límite en 100 o más, y utilícelo para su adaptador. Si el usuario se desplaza hasta la parte inferior de la lista, podría agregar una fila con una ProgressBar o indicar de otro modo que hay más por venir.

Una vez que su segundo hilo está hecho, reemplace el adaptador.

Como alternativa, podría tener un adaptador de matriz o algo similar, hacer un montón de consultas en el segundo subproceso con 100 filas cada uno, y agregarlos a su adaptador de matriz a medida que vienen. Eso también haría más fácil agregar una fila ficticia en La parte inferior que indica a los usuarios a celebrar sus caballos.

Una nota – yo asumiría que es seguro leer de la base de datos de dos hilos al mismo tiempo, pero tenga cuidado cuando se trata de escribir. Mi aplicación tenía un error maravilloso en el que trashed la base de datos cuando tenía las operaciones de base de datos en un hilo separado hasta que agregó bloqueo adecuado (que también se puede activar en la base de datos).

EDIT: Por supuesto, AsyncQueryHandler, sabía que había algo así, pero no podía recordar el nombre. Más elegante que un hilo separado, por supuesto.

Btw – ¿cómo se almacena la base de datos? ¿Es sólo un archivo de base de datos regular en su almacenamiento interno?

Hola estoy tratando de lograr esto con más de 50000rows. Creo que mi código puede dar u los mejores resultados para u como u tienen sólo 8000 registros.

1) utilizar el proveedor de contenido en lugar de sqlite. 2) utilizar loadermanager callbacks para cargar el cursor de forma asincrónica 3) para la búsqueda de utilizar tablas FTS. 4) optimizar ur db con la indexación también.

Confía en mí funciona muy bien con 8000 filas incluso con sectionIndexer y con desplazamiento rápido también.

Déjame saber si tienes dudas.

Ps si u encontrado una solución mejor, que u piensa puede manejar 50000 filas por favor hágamelo saber.

  • CursorIndexOutOfBoundsException Index 0 solicitado, con un tamaño de 0
  • Android - Firebase Offline Mejores Prácticas
  • Error de base de datos SQLite de SQL cuando intenta insertar en la tabla
  • Comprobación de SQLite de SQL si las tablas contienen filas
  • Aplicación de diccionario androide con base de datos sin conexión
  • ¿Cómo puedo crear una base de datos en android?
  • Pros y contras de SQLite y preferencias compartidas
  • Android - ¿Dónde está la base de datos SQLite almacenada
  • ViewPager y base de datos
  • Se filtró un objeto SQLiteConnection para la base de datos. Por favor, corrija su aplicación
  • Método personalizado de Android en el proveedor de contenido para obtener el número de registros en la tabla?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.