Jak uzyskać kontekst w adapterze widoku recyklera

129

Próbuję użyć biblioteki Picasso, aby móc załadować adres URL do imageView, ale nie mogę uzyskać prawidłowego contextkorzystania z biblioteki 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();
    }

}
Nieznajomy B.
źródło

Odpowiedzi:

290

Masz tutaj kilka opcji:

  1. Przekaż Contextjako argument do FeedAdapter i zachowaj go jako pole klasy
  2. Użyj zastrzyku zależności, aby wstrzyknąć, Contextgdy tego potrzebujesz. Gorąco zachęcam do przeczytania o tym. Jest do tego świetne narzędzie - Dagger by Square
  3. Zdobądź to z dowolnego Viewobiektu. W Twoim przypadku może to zadziałać:

    holder.pub_image.getContext()

    Jak pub_imagejest ImageView.

pelotasplus
źródło
64
Wolę trzecią opcję, aby uzyskać kontekst z widoku. To najprostsze i najprostsze rozwiązanie.
Dick Lucas
lub, znacznie lepiej, przejdź do instancji Picassa, zamiast trzymać instancję Picassa na instancji klasy i ładować ją leniwie.
Eric Cochran
8
Każdy ViewHolder zawiera instancję itemView, która jest przekazywana w konstruktorze. Użyj tego w ten sposób: itemView.getContext ()
Andrei Lupsa
1
Nie możesz zrobić nr 2, prawda? Próbowałem tego, ale to zakończy się twoim ApplicationContexti nie będzie związane z działaniem, co doprowadzi do awarii środowiska wykonawczego z poziomu Glide.
boltup_im_coding
jak przekazać obiekt komponentu do adaptera w przypadku, gdy chcę użyć # 2?
Ezio
32

Możesz dodać zmienną globalną:

private Context context;

następnie przypisz kontekst stąd:

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

Miłego kodowania :)

Farhad Navayazdan
źródło
U mnie też zadziałało! Dzięki
Kenny Dabiri
21
Zdecydowanie radzę PRZECIWKO mieć globalne odniesienia do kontekstu. Może to prowadzić do strasznych problemów z wyciekiem pamięci!
solidak
1
jeśli tworzysz podklasę viewholder, może być prywatny.
r3dm4n
Jeśli adapter jest dołączony do RecyclerView, wtedy ten kontekst jest i tak potrzebny. Jeśli możesz odłączyć adapter, to nadal jest w porządku, chyba że z jakiegoś powodu masz silne odniesienie do tego adaptera po jego odłączeniu, w takim przypadku powinieneś wyczyścić buforowany kontekst, istnieje metoda podobna onDetachedFromRecyclerViewlub coś w tym rodzaju.
androidguy
19

Krótka odpowiedź:

Context context;

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

Wyjaśnienie, dlaczego inne odpowiedzi nie są świetne:

  1. Przechodzenie Contextdo adaptera jest całkowicie niepotrzebne, ponieważ RecyclerViewmożna uzyskać do niego dostęp z poziomu klasy
  2. Uzyskiwanie Contextna ViewHolderpoziomie oznacza, że ​​robisz to za każdym razem, gdy wiążesz lub tworzysz plik ViewHolder. Powielasz operacje.
  3. Myślę, że nie musisz się martwić o wyciek pamięci. Jeśli twój adapter pozostaje poza twoją Activityżywotnością (co byłoby dziwne), masz już wyciek.
Maciej Beimcik
źródło
W takim przypadku, czy zaimplementujemy onDetachedFromRecyclerView()i zwolnimy kontekst?
John Pang
@JohnPang nie bardzo, chyba że chcesz być wyjątkowo defensywny. Jeśli zachowasz odniesienie do adaptera w działaniu, jesteś bezpieczny.
Maciej Beimcik
17

Możesz użyć kontekstu pub_image ( 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);


}
Ahmad Aghazadeh
źródło
6

Możesz zdefiniować:

Context ctx; 

Po onCreateinicjalizacji ctx:

ctx=parent.getContext(); 

Uwaga: rodzic to ViewGroup.

Marcos Vitouley
źródło
5

Najpierw zadeklaruj globalnie

Context mContext;

przekazać kontekst konstruktorowi, modyfikując go.

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

następnie użyj tego, mContextgdzie go potrzebujesz

Blue_Alien
źródło
5

Możesz użyć w ten sposób view.getContext ()

Przykład

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

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


        }
    });
Arpit Patel
źródło
5

możesz użyć tego:

itemView.getContext()
张家 宝
źródło
4

Utwórz konstruktora FeedAdapter:

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

i w Aktywności

FeedAdapter obj = new FeedAdapter(this);
blockwala
źródło
2

Najpierw dodaj zmienną globalną

Context mContext;

Następnie zmień konstruktora na ten

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

Przekaż kontekst podczas tworzenia adaptera.

FeedAdapter myAdapter = new FeedAdapter(this,myDataset);
AKT
źródło
1
View mView;
mView.getContext();
Rohit Daftari
źródło
Chociaż ten kod może rozwiązać problem, w tym wyjaśnienie, jak i dlaczego to rozwiązuje problem, naprawdę pomogłoby poprawić jakość twojego posta i prawdopodobnie zaowocowałoby większą liczbą pozytywnych głosów. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a nie tylko osoba, która zapyta teraz. Proszę edytować swoje odpowiedzi, aby dodać wyjaśnień i dać wskazówkę co zastosować ograniczenia i założenia. Z recenzji
podwójny sygnał