So erhalten Sie einen Kontext in einem Recycler-Ansichtsadapter


128

Ich versuche, die Picasso-Bibliothek zu verwenden, um eine URL in imageView laden zu können, aber ich kann contextdie Picasso-Bibliothek nicht richtig verwenden.

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();
    }

}

Antworten:


289

Sie haben hier einige Möglichkeiten:

  1. Übergeben Sie Contextals Argument an FeedAdapter und halten es als Klassenfeld
  2. Verwenden Sie die Abhängigkeitsinjektion, um Contextbei Bedarf zu injizieren . Ich empfehle dringend, darüber zu lesen. Dafür gibt es ein großartiges Werkzeug - Dagger by Square
  3. Holen Sie es von jedem ViewObjekt. In Ihrem Fall könnte dies für Sie funktionieren:

    holder.pub_image.getContext()

    Da pub_imageist ein ImageView.


64
Ich bevorzuge die dritte Option, den Kontext aus der Ansicht zu erhalten. Es ist die einfachste und einfachste Lösung.
Dick Lucas

oder, viel besser, übergeben Sie die Picasso-Instanz, anstatt eine Picasso-Instanz auf der Klasseninstanz zu halten und sie faul zu laden.
Eric Cochran

8
Jeder ViewHolder enthält eine Instanz von itemView, die Sie im Konstruktor übergeben. Verwenden Sie diese wie folgt: itemView.getContext ()
Andrei Lupsa

1
Sie können nicht # 2 tun, oder? Ich habe das versucht, aber dies wird am Ende Ihre sein ApplicationContextund nicht an die Aktivität gebunden sein, was zu einem Laufzeitabsturz innerhalb von Glide führt.
Boltup_im_coding

Wie übergebe ich das Komponentenobjekt an den Adapter, falls ich # 2 verwenden möchte?
Ezio

32

Sie können eine globale Variable hinzufügen:

private Context context;

Weisen Sie dann den Kontext von hier aus zu:

@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;
}

Happy Codding :)


Hat auch für mich gearbeitet! Vielen Dank
Kenny Dabiri

21
Ich empfehle dringend, GEGEN globale Verweise auf den Kontext zu haben. Dies könnte zu schrecklichen Speicherverlustproblemen führen !!
Solidak

1
Wenn Sie den Ansichtsinhaber unterordnen, kann er privat sein.
r3dm4n

Wenn der Adapter an eine RecyclerView angeschlossen ist, wird dieser Kontext garantiert trotzdem benötigt. Wenn Sie den Adapter möglicherweise trennen, ist dies immer noch in Ordnung, es sei denn, Sie haben aus irgendeinem Grund einen starken Verweis auf diesen Adapter, nachdem er getrennt wurde. In diesem Fall sollten Sie den zwischengespeicherten Kontext löschen. Es gibt eine Methode wie onDetachedFromRecyclerViewoder so.
AndroidGy

19

Kurze Antwort:

Context context;

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

Erklärung, warum andere Antworten nicht großartig sind:

  1. Die Übergabe Contextan den Adapter ist völlig unnötig, da RecyclerViewSie innerhalb der Klasse darauf zugreifen können
  2. Das Erhalten Contextauf ViewHolderEbene bedeutet, dass Sie dies jedes Mal tun, wenn Sie eine binden oder erstellen ViewHolder. Sie duplizieren Operationen.
  3. Ich glaube nicht, dass Sie sich über Speicherverluste Sorgen machen müssen. Wenn Ihr Adapter außerhalb Ihrer ActivityLebensdauer verweilt (was seltsam wäre), haben Sie bereits ein Leck.

Sollen wir in diesem Fall den onDetachedFromRecyclerView()Kontext implementieren und freigeben?
John Pang

@ JohnPang nicht wirklich, es sei denn, Sie wollen extrem defensiv sein. Wenn Sie die Adapterreferenz in der Aktivität behalten, sind Sie sicher.
Maciej Beimcik

17

Sie können pub_image context ( holder.pub_image.getContext()) verwenden:

@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

Sie können definieren:

Context ctx; 

Und bei der onCreateInitialisierung ctxzu:

ctx=parent.getContext(); 

Hinweis: Übergeordnet ist eine ViewGroup.


5

Zuerst global deklarieren

Context mContext;

Übergeben Sie den Kontext mit dem Konstruktor, indem Sie ihn ändern.

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

mContextVerwenden Sie dann das, wo immer Sie es brauchen


5

Sie können wie folgt view.getContext () verwenden

Beispiel

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

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


        }
    });


4

Erstellen Sie einen Konstruktor von FeedAdapter:

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

und in Aktivität

FeedAdapter obj = new FeedAdapter(this);

2

Fügen Sie zuerst eine globale Variable hinzu

Context mContext;

Ändern Sie dann Ihren Konstruktor in diesen

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

Übergeben Sie Ihren Kontext beim Erstellen des Adapters.

FeedAdapter myAdapter = new FeedAdapter(this,myDataset);

1
View mView;
mView.getContext();

Während dieser Code die Frage lösen kann, einschließlich einer Erklärung, wie und warum dies das Problem löst, würde dies wirklich dazu beitragen, die Qualität Ihres Beitrags zu verbessern, und wahrscheinlich zu mehr Up-Votes führen. Denken Sie daran, dass Sie in Zukunft die Frage für die Leser beantworten, nicht nur für die Person, die jetzt fragt. Bitte bearbeiten Sie Ihre Antwort, um Erklärungen hinzuzufügen und anzugeben, welche Einschränkungen und Annahmen gelten. Aus der Überprüfung
doppelter Piepton
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.