2011-06-05 1 views
10

Disons que je prolonge ArrayAdapter et dans le code où je surcharge getView(int i, View v, ViewGroup g), je récupère l'article courant en utilisant getItem(i). Puis-je être sûr que getItem(i) retournera un élément même si d'autres threads manipulent le même ?Le thread ArrayAdapter est-il sécurisé dans android? Si non, que puis-je faire pour le rendre sûr?

Je ne suis pas sûr, mais je pense que la réponse est non. Si c'est le cas, que suggérez-vous que je fasse pour qu'il soit sans danger pour les fils?

Répondre

27

Il ne s'agit pas d'ArrayAdapter étant thread-safe. ListView et d'autres widgets d'interface utilisateur fonctionnant avec un adaptateur n'autorisent pas le changement inattendu du contenu de l'adaptateur. Et ce n'est pas seulement dû à d'autres threads: vous devez indiquer à ListView la modification que vous effectuez avant d'essayer d'interagir avec votre adaptateur. Si vous autorisez un autre thread à modifier l'adaptateur, ou si vous le modifiez sur le thread principal sans en avertir ListView avant d'autoriser quoi que ce soit d'autre, vous obtiendrez au hasard (en raison des courses) des exceptions lancées par ListView à propos de l'adaptateur change de façon inattendue.

Dans le cas spécifique de ArrayAdapter si vous utilisez l'API pour modifier son contenu, il se chargera de dire à la vue de liste sur la modification. Cependant vous devez faire de tels changements sur le thread principal, pour vous assurer que la vue de liste n'essaie pas d'accéder à l'adaptateur entre le point où votre modification est faite et la vue de liste est informée de ce changement.

Si vous effectuez des modifications simples à ArrayAdapter (en ajoutant et supprimant quelques éléments), tout ira bien, mais vous devez le faire sur le thread principal. Pour des changements plus importants (comme dire que l'adaptateur obtient un nouvel ensemble de données en raison d'une extraction de nouvelles données à partir d'un serveur), ne pas utiliser ArrayAdapter et implémenter votre propre sous-classe de BaseAdapter. ArrayAdapter est conçu pour les situations où vous avez un petit ensemble de données assez statique pour montrer des situations simples. Pour les choses plus compliquées, vous serez probablement plus content d'implémenter BaseAdapter et de faire vous-même la gestion des données. La manière typique dont un adaptateur est mis à jour dans ces situations compliquées est qu'un thread d'arrière-plan génère le nouvel ensemble de données, et une fois qu'il est disponible, il est alors atomisé sur l'adaptateur avec un appel à notifyDataSetChanged() pour laisser le ListView savoir que les données ont changé. Donc, disons que vous montrez des données qui sont un tableau d'objets MyItem.Gardez vos données dans un tableau de jeu:

ArrayList<MyItem> 

Mettre en oeuvre une sous-classe de BaseAdapter qui montre cette liste:

class MyAdapter extends BaseAdapter<MyItem> { 
    ArrayList<MyItem> mItems; 

    public int getCount() { 
     return mItems != null ? mItems.size() : 0; 
    } 

    public MyItem getItem(int position) { 
     return mItems.get(i); 
    } 

    ... 
} 

Et maintenant, voici une fonction que vous pourriez mettre en œuvre sur l'adaptateur qui peut être appelé à partir d'une autre fil pour fournir une nouvelle série de données à afficher:

final Handler mHandler = new Handler(); 

    void setDataFromAnyThread(final ArrayList<MyItem> newData) { 
     // Enqueue work on mHandler to change the data on 
     // the main thread. 
     mHandler.post(new Runnable() { 
       @Override 
       public void run() { 
        mItems = newData; 
        notifyDataSetChanged(); 
       } 
      }); 
    } 

Bien sûr, si vous utilisez AsyncTask pour faire votre génération de données ce qui a déjà une installation pratique pour effectuer cette travailler sur le fil principal. De même, vous pouvez utiliser la nouvelle fonctionnalité Loader pour prendre en charge la génération en arrière-plan. Et si vous voulez toujours utiliser ArrayAdapter, dans votre fonction ci-dessus, vous pouvez le faire en effaçant les données actuelles et en ajoutant les nouvelles données à l'adaptateur maintenant vide. C'est juste plus de frais généraux qui ne vous apporte vraiment rien.

4

L'adaptateur de matrice n'est pas adapté aux threads. Je l'ai vu planter en raison de problèmes de concurrence. L'adaptateur de tableau convertira uniquement votre tableau sur une vue du thread principal (GUI). Donc, si vous faites attention à ne jamais modifier le tableau (ajouter ou supprimer) sur le thread principal, vous pouvez vous assurer qu'il ne fonctionnera que sur 1 thread.

+0

bien, résolu mon problème. THX – 2red13

Questions connexes