2009-08-26 4 views
2

Cette application sur laquelle je travaille a des bases de données avec plusieurs mégaoctets de données à passer au crible. Beaucoup d'activités sont juste ListViews descendant à travers différents niveaux de données dans les bases de données jusqu'à ce que nous atteignions "documents", qui est juste HTML à tirer de la DB (s) et affiché sur le téléphone. Le problème que j'ai est que certaines de ces activités doivent avoir la capacité de rechercher dans les bases de données en capturant des frappes et en réexécutant la requête avec un "comme% blah%" dedans. Cela fonctionne assez rapidement, sauf lorsque l'utilisateur charge les données pour la première fois et lorsque l'utilisateur saisit une première frappe. J'utilise un ResourceCursorAdapter et je génère le curseur dans un thread d'arrière-plan, mais pour faire un listAdapter.changeCursor(), je dois utiliser un gestionnaire pour le publier dans le thread d'interface utilisateur principal. Cet appel particulier gèle alors le thread d'interface utilisateur juste assez longtemps pour faire apparaître la redoutée boîte de dialogue ANR. Je suis curieux de savoir comment je peux décharger cela sur un thread d'arrière-plan afin que l'interface utilisateur reste réactive et que les boîtes de dialogue ANR ne s'affichent pas. Juste pour la divulgation complète, je retournais à l'origine une ArrayList d'objets de modèle personnalisé et en utilisant un ArrayAdapter, mais (compréhensible) le client a souligné qu'il était mauvaise gestion de la mémoire et je n'étais pas satisfait de la performance de toute façon. Je voudrais vraiment éviter une solution où je générer des listes énormes d'objets, puis faire un listAdapter.notifyDataSetChanged/Invalidated()Android CursorAdapters, ListViews et les threads d'arrière-plan

Voici le code en question:

private Runnable filterDrugListRunnable = new Runnable() { 
    public void run() { 
     if (filterLock.tryLock() == false) return; 

     cur = ActivityUtils.getIndexItemCursor(DrugListActivity.this); 

     if (cur == null || forceRefresh == true) { 
      cur = docDb.getItemCursor(selectedIndex.getIndexId(), filter); 
      ActivityUtils.setIndexItemCursor(DrugListActivity.this, cur); 
      forceRefresh = false; 
     } 

     updateHandler.post(new Runnable() { 
      public void run() { 
       listAdapter.changeCursor(cur); 
      } 
     }); 

     filterLock.unlock(); 

     updateHandler.post(hideProgressRunnable); 
     updateHandler.post(updateListRunnable); 
    } 
}; 

Répondre

1

Je trouve Il est difficile de croire que listAdapter.changeCursor() prendrait suffisamment de temps pour provoquer un ANR, en supposant que vous ayez créé Cursor dans un thread d'arrière-plan. Il ne devrait pas y avoir autant de travail qui doit arriver pour repeindre une poignée de lignes de la liste. Je revérifierais pour voir ce que vous faites dans votre Handler est aussi limité que vous le pensez. Peut-être envisager d'utiliser un AsyncTask, ce qui facilite la séparation du travail en arrière-plan (doInBackground()) du post-traitement de threads-UI (onPostExecute()).

Vous pouvez essayer de remplacer purement et simplement l'adaptateur, en appelant à nouveau setAdapter() avec le nouveau Cursor enveloppé dans un nouvel adaptateur.

Vous pouvez voir comment AutoCompleteTextView gère ce scénario, car il effectue un filtrage à la volée avec un SpinnerAdapter. Peut-être que certaines de ses techniques peuvent s'appliquer dans votre cas.

+0

Avant ajouté l'appel changeCursor, tout était heureux et a couru en arrière-plan. Une fois que j'ajouté ceci: updateHandler.post (nouveau Runnable() { public void run() { listAdapter.changeCursor (roquet);} }); Tout est allé à la connerie rapidement. – MattC

+0

Question d'étrange: qu'est-ce que filterLock dans votre code ci-dessus? Êtes-vous en train de courir dans une étreinte mortelle ou une impasse? – CommonsWare

+0

C'est juste un verrou que nous avions prévu d'utiliser au cas où l'utilisateur continuerait à taper pendant que la première requête était en cours d'exécution. En parcourant le code actuel du CursorAdapter, changeCursor appelle notifyDataSetChanged() et c'est là qu'il est suspendu. – MattC

Questions connexes