À l'aide du Curseur avec ListView adaptateur pour une grande quantité de données
je suis en utilisant une mesure CursorAdapter pour obtenir des données à partir d'une base de données SQLite et l'afficher dans un contrôle listview. Cette base de données contient 2 colonnes avec environ 8.000 lignes. donc, je suis à la recherche d'un moyen d'interroger et de montrer toutes les données aussi rapidement que possible. je l'ai fait avec asyncTask voici le code:
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();
}
}
cela fonctionne bien sauf la partie quand j'ai besoin de mettre le résultat dans un adaptateur. j'ai fait quelques tests de temps et il faut environ 700 ms pour faire passé le startManagingCursor. le problème est que cela prend environ 7 secondes pour le faire passé le setAdapter(suite) et c'est en cours d'exécution dans le thread de l'INTERFACE utilisateur de sorte qu'il rend mon application ne répond pas (la boîte de dialogue de progression se fige et ne sont, parfois, de l'application). comment puis-je faire de ce temps? puis-je faire cela aussi s'exécuter en arrière-plan ou un moyen d'augmenter la réactivité?
tnx.
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());
}
}
}
j'ai un fastscroll avec l'indexation mis en œuvre. et je vais ajouter une option de recherche plus tard à filtre.
En tout cas, on POURRAIT faire la requête dans un thread séparé et à l'attribuer à la carte, mais qui laisserait de votre application noir pendant 7 secondes. Sauf si vous avez un moyen de divertir l'utilisateur pendant 7 secondes?
bien le point de l'ensemble de l'application est d'avoir cette quantité de données. L'utilisateur doit être capable de faire défiler librement et ensuite choisir quelque chose de le filtrer pour plus d'info pertinente, et comme je l'ai dit, l'option de recherche vont le faire aussi. mais il doit être capable de faire défiler afin qu'il puisse se faire une idée de ce qu'il faut rechercher.
Je suis en train de faire quelque chose de similaire ICI stackoverflow.com/questions/10224233/...
OriginalL'auteur DArkO | 2010-12-02
Vous devez vous connecter pour publier un commentaire.
La raison de la lenteur des temps de chargement de la carte est l'appel interne en la CursorAdapter rend à la position du Curseur.getCount().
Curseurs dans Android sont paresseusement chargé. Les résultats ne sont pas chargés jusqu'à ce qu'ils sont nécessaires. Lorsque la CursorAdapter appels getCount (), c'forces de la requête pour être pleinement mis en œuvre et les résultats comptés.
Ci-dessous, quelques liens de discuter de cette question.
http://groups.google.com/group/android-developers/browse_thread/thread/c1346ec6e2310c0c
http://www.androidsoftwaredeveloper.com/2010/02/25/sqlite-performance/
Ma suggestion serait de diviser votre requête. Charger uniquement le nombre de visible les éléments de la liste à l'écran. En tant que l'utilisateur fait défiler la charge de la prochaine série. Très bien comme GMail et applications dans le Marché. Malheureusement je n'ai pas un exemple pratique 🙁
Ce n'est pas la réponse à votre question, mais j'espère qu'il a une idée 🙂
OriginalL'auteur Jason L.
Ne sais pas pourquoi setAdapter devrait prendre autant de temps. J'ai fait environ 5000 lignes beaucoup plus vite que ça. Cependant, j'ai l'habitude de créer un adaptateur sans un curseur d'abord, appel setAdapter avec le "vide" de l'adaptateur, puis le coup d'envoi d'une requête asynchrone à l'aide d'un AsyncQueryHandler sous-classe. Puis, dans onQueryComplete, j'appelle changeCursor sur la carte.
OriginalL'auteur dhaag23
Bien, je peux vous offrir un muet suggestion à ce point de commencer une requête dans un thread séparé qui passeront par l'ensemble de la base de données et créer votre 8000-ligne du curseur.
Dans votre thread de l'INTERFACE utilisateur, créer un curseur permet de régler la limite de 100, et l'utiliser pour votre carte. Si l'utilisateur fait défiler vers le bas de votre liste, vous pouvez ajouter une ligne avec une ProgressBar ou indiquent le contraire qu'il n'y a plus à venir.
Une fois que votre deuxième thread est fait, remplacer la carte.
Sinon, vous pourriez avoir un adaptateur tableau ou quelque chose de similaire, faire un tas de requêtes dans le deuxième thread avec 100 lignes chacune, et de les ajouter à votre tableau à l'adaptateur, comme ils viennent. Cela rendrait aussi plus facile d'ajouter une ligne fictive en bas qui indique aux utilisateurs de tenir leurs chevaux.
Une note, je suppose que c'est sécuritaire de le lire à partir de la base de données à partir de deux threads en même temps, mais être prudent quand il vient à l'écriture. Mon application a un magnifique bug où il saccagé la base de données lorsque j'ai eu des opérations de base de données dans un thread séparé jusqu'à ce que j'ai ajouté bon verrouillage (que vous pouvez également activer dans la base de données).
EDIT: bien sûr, AsyncQueryHandler, je savais qu'il y avait quelque chose comme ça, mais je ne me souviens pas le nom. De plus élégant qu'un thread séparé, bien sûr.
Btw - comment êtes-vous stocker la base de données? Est-il juste un fichier de base de données dans votre espace de stockage interne?
Oh génial, j'ai mal lu. Quel type de carte que vous utilisez? Je vois CustomCursorAdapter - quelle est la partie personnalisée?
Il s'étend SimpleCursorAdapter. voici ce que j'ai utilisé pour le faire. thinkandroid.wordpress.com/2010/01/11/custom-cursoradapters
Hmm... très anodin. La seule chose que j'ai pu trouver avec une recherche rapide sur google était le genre de ce que j'ai suggéré d'utiliser un petit jeu à la première et à l'étendre. Regardez ce fil. Romain dit qu'il y a une API de démonstration pour ça aussi: groups.google.com/group/android-developers/browse_thread/thread/...
j'ai posté mon code d'adaptateur dans l'édition de ma question.
OriginalL'auteur EboMike
hi im essayant de réaliser cela avec plus de 50000rows. je pense que mon code peut donner u les meilleurs résultats pour u, u ont seulement 8000 enregistrements.
1)utilisez un fournisseur de contenu au lieu de sqlite.
2)utiliser loadermanager rappels à la charge du curseur en mode asynchrone
3)pour la recherche de l'utilisation FTS tables.
4)optimiser ur db avec une indexation trop.
confiance en moi, il fonctionne très bien avec 8000 lignes, même avec sectionIndexer et avec défilement rapide de trop.
laissez-moi savoir si u avez des doutes.
P. s si u trouvé une meilleure solution , u pense que peut gérer 50000 lignes s'il vous plaît laissez-moi savoir.
OriginalL'auteur oops.objective