Comment obtenir un contexte dans un adaptateur de vue recycleur


129

J'essaie d'utiliser la bibliothèque Picasso pour pouvoir charger l'URL dans imageView, mais je ne suis pas en mesure d'obtenir le contextpour utiliser correctement la bibliothèque Picasso.

public class FeedAdapter extends RecyclerView.Adapter<FeedAdapter.ViewHolder> {
    private List<Post> mDataset;



    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder
    public class ViewHolder extends RecyclerView.ViewHolder {
        // each data item is just a string in this case
        public TextView txtHeader;
        public ImageView pub_image;
        public ViewHolder(View v) {
            super(v);
            txtHeader = (TextView) v.findViewById(R.id.firstline);
            pub_image = (ImageView) v.findViewById(R.id.imageView);


        }
    }




    // Provide a suitable constructor (depends on the kind of dataset)
    public FeedAdapter(List<Post> myDataset) {
        mDataset = myDataset;
    }

    // Create new views (invoked by the layout manager)
    @Override
    public FeedAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                   int viewType) {
        // create a new view
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.feedholder, parent, false);
        // set the view's size, margins, paddings and layout parameters
        ViewHolder vh = new ViewHolder(v);
        return vh;
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element

        holder.txtHeader.setText(mDataset.get(position).getPost_text());

        Picasso.with(this.context).load("http://i.imgur.com/DvpvklR.png").into(holder.pub_image);


    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mDataset.size();
    }

}

Réponses:


290

Vous avez ici quelques options:

  1. Passez Contexten argument à FeedAdapter et conservez-le comme champ de classe
  2. Utilisez l'injection de dépendances pour injecter Contextlorsque vous en avez besoin. Je suggère fortement de lire à ce sujet. Il existe un excellent outil pour cela - Dagger by Square
  3. Obtenez-le de n'importe quel Viewobjet. Dans votre cas, cela pourrait fonctionner pour vous:

    holder.pub_image.getContext()

    Comme pub_imagec'est un ImageView.


64
Je préfère la troisième option, obtenir le contexte de la vue. C'est la solution la plus simple et la plus directe.
Dick Lucas

ou, mieux encore, transmettez l'instance Picasso, plutôt que de maintenir une instance Picasso sur l'instance de classe et de la charger paresseusement.
Eric Cochran

8
Chaque ViewHolder contient une instance de itemView que vous transmettez au constructeur. Utilisez celui-ci comme ceci: itemView.getContext ()
Andrei Lupsa

1
Vous ne pouvez pas faire le n ° 2, n'est-ce pas? J'ai essayé cela, mais cela finira par être le vôtre ApplicationContextet non lié à l'activité, ce qui entraînera un crash d'exécution à partir de Glide.
boltup_im_coding

comment passer l'objet composant à l'adaptateur au cas où je voudrais utiliser # 2?
Ezio

32

Vous pouvez ajouter une variable globale:

private Context context;

puis attribuez le contexte à partir d'ici:

@Override
public FeedAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
    // create a new view
    View v=LayoutInflater.from(parent.getContext()).inflate(R.layout.feedholder, parent, false);
    // set the view's size, margins, paddings and layout parameters
    ViewHolder vh = new ViewHolder(v);
    // set the Context here 
    context = parent.getContext();
    return vh;
}

Bon codding :)


A travaillé pour moi aussi! Merci
Kenny Dabiri

21
Je suggère fortement CONTRE d'avoir des références globales au contexte. Cela pourrait entraîner d'horribles problèmes de fuite de mémoire !!
solidak

1
si vous sous-classez le visualiseur, il peut être privé.
r3dm4n

Si l'adaptateur est attaché à un RecyclerView, il est garanti que ce contexte est de toute façon nécessaire. Si vous pouvez détacher l'adaptateur, alors tout va bien sauf si, pour une raison quelconque, vous détenez une référence forte à cet adaptateur après qu'il a été détaché, auquel cas vous devez effacer le contexte mis en cache, il existe une méthode comme onDetachedFromRecyclerViewou quelque chose.
androidguy

19

Réponse courte:

Context context;

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
    context = recyclerView.getContext();
}

Explication pourquoi les autres réponses ne sont pas géniales:

  1. Le passage Contextà l'adaptateur est totalement inutile, car RecyclerViewvous pouvez y accéder depuis l'intérieur de la classe
  2. Obtenir Contextau ViewHolderniveau signifie que vous le faites chaque fois que vous liez ou créez unViewHolder . Vous dupliquez des opérations.
  3. Je ne pense pas que vous ayez à vous soucier d'une fuite de mémoire. Si votre adaptateur persiste en dehors de votre Activitydurée de vie (ce qui serait étrange), vous avez déjà une fuite.

Dans ce cas, devons-nous implémenter onDetachedFromRecyclerView()et libérer le contexte?
John Pang

@JohnPang pas vraiment à moins que vous ne vouliez être extrêmement défensif. Si vous conservez la référence de l'adaptateur dans l'activité, vous êtes en sécurité.
Maciej Beimcik

17

Vous pouvez utiliser pub_image context ( holder.pub_image.getContext()):

@Override
public void onBindViewHolder(ViewHolder ViewHolder, int position) {

    holder.txtHeader.setText(mDataset.get(position).getPost_text());

    Picasso.with(holder.pub_image.getContext()).load("http://i.imgur.com/DvpvklR.png").into(holder.pub_image);


}

6

Vous pouvez définir:

Context ctx; 

Et lors de l' onCreateinitialisation ctxsur:

ctx=parent.getContext(); 

Remarque: Parent est un ViewGroup.


5

Première déclaration mondiale

Context mContext;

passer le contexte au constructeur, en le modifiant.

public FeedAdapter(List<Post> myDataset, Context context) {
    mDataset = myDataset;
    this.mContext = context;
}

puis utilisez le mContextpartout où vous en avez besoin


5

Vous pouvez utiliser comme ceci view.getContext ()

Exemple

holder.tv_room_name.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Toast.makeText(v.getContext(), "", Toast.LENGTH_SHORT).show();


        }
    });

5

vous pouvez utiliser ceci:

itemView.getContext()

4

Créez un constructeur de FeedAdapter:

Context context; //global
public FeedAdapter(Context context)
{
   this.context = context;  
}

et en activité

FeedAdapter obj = new FeedAdapter(this);

2

Ajoutez d'abord une variable globale

Context mContext;

Puis changez votre constructeur en ceci

public FeedAdapter(Context context, List<Post> myDataset) {
    mContext = context;
    mDataset = myDataset;
}

Passez votre contexte lors de la création de l'adaptateur.

FeedAdapter myAdapter = new FeedAdapter(this,myDataset);

1
View mView;
mView.getContext();

Bien que ce code puisse résoudre la question, inclure une explication sur comment et pourquoi cela résout le problème aiderait vraiment à améliorer la qualité de votre message et entraînerait probablement plus de votes à la hausse. N'oubliez pas que vous répondez à la question des lecteurs à l'avenir, pas seulement à la personne qui la pose maintenant. Veuillez modifier votre réponse pour ajouter des explications et donner une indication des limites et des hypothèses applicables. De l'avis
double-beep
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.