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(); }
}
- Cómo establecer la contraseña como píxeles de la imagen en android (punto de clic cued o contraseña grapical)
- La base de datos Android está dañada, pero puede abrirse en SQLite Manager. ¿Recuperable?
- Cómo almacenar JSON en SQLite
- ¿Es mejor pasar los datos por intención o consultar la base de datos cuando sea necesario?
- Cómo proteger una base de datos sqlite pre hecho en android?
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()); } } }
- Cómo eliminar la base de datos en la aplicación para Android
- SetSelection en Spinner basado en rowId
- Evite borrar los datos de la base de datos al hacer clic en el botón "borrar datos" en la configuración de la aplicación en el dispositivo Android
- Android sqlite eliminar consulta no funciona
- ¿Cómo implementar deshacer un solo paso para los cambios en la base de datos SQLite?
- ¿Cómo conectar el teléfono de android a un servicio de la tela funcionado en el servidor local?
- Eliminar archivo de base de datos de la carpeta de activos
- Aplicación de Android (Samsung Galaxy Tab, 2.2) no * a veces * escribir en el DB
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.
- Cómo programar la notificación en Android
- Es posible copia de seguridad y restaurar un archivo de base de datos en android? Dispositivos no root